SpringSecurity主要扩展点
主体数据来源:通过自己实现一个UserDetailsService对象并注入到Spring容器 中,来实现自定义的主体数据管理
package com.vn.config; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * @author VN * 致敬未来的你 * @date 2022/6/25 14:20 * * 主体数据来源 */ public class MyUserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { if ("vn".equals(username)){ return User.withUsername("vn").password("123456").authorities("mobile", "salary").build(); } return null; } }
package com.vn.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.JdbcUserDetailsManager; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.sql.DataSource; @Configuration public class MyWebConfig implements WebMvcConfigurer { //默认Url根路径跳转到/login,此url为spring security提供 @Override public void addViewControllers(ViewControllerRegistry registry) { // spring security提供默认路径 // registry.addViewController("/").setViewName("redirect:/login"); // 自定义跳转路径 registry.addViewController("/").setViewName("redirect:/index.html"); } /** * 自行注入一个PasswordEncoder。 * Security会优先从Spring容器中获取PasswordEncoder. * 注入一个不做任何加解密操作的密码处理器用作演示。 * 一般常用BCryptPasswordEncoder * * @return */ @Bean public PasswordEncoder getPassWordEncoder() { // return new BCryptPasswordEncoder(10); return NoOpPasswordEncoder.getInstance(); } /** * 自行注入一个UserDetailsService * 如果没有的话,在UserDetailsServiceAutoConfiguration中会默认注入一个包含user用户的InMemoryUserDetailsManager * * @return */ @Bean public UserDetailsService userDetailsService() { // InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(User.withUsername("admin").password("admin").authorities("mobile", "salary").build() // , User.withUsername("manager").password("manager").authorities("salary").build() // , User.withUsername("worker").password("worker").roles("worker").build()); // return userDetailsManager; // return new JdbcUserDetailsManager(DataSource dataSource); return new MyUserService(); } }
自定义授权及安全拦截策略
自定义登录:
http.loginPage()方法配置登录页,http.loginProcessingUrl()方法定制登录逻辑
//配置安全拦截策略 @Override protected void configure(HttpSecurity http) throws Exception { //链式配置拦截策略 http .csrf().disable()//关闭csrg跨域检查 //这里注意matchere是有顺序的。 .authorizeRequests() .antMatchers("/mobile/**").hasAuthority("mobile") .antMatchers("/salary/**").hasAuthority("salary") .antMatchers("/worker/**").hasAuthority("ROLE_worker")//等价于hasRole("worker") .antMatchers("/common/**").permitAll() //common下的请求直接通过 .antMatchers("/**.html","/js/**","/css/**","/img/**").permitAll()//放行静态资源 .anyRequest().authenticated() //其他请求需要登录 .and()//并行条件 .formLogin() .loginPage("/index.html").loginProcessingUrl("/login")//自定义登录页面 .defaultSuccessUrl("/main.html").failureUrl("/common/loginFailed"); //可从默认的login页面登录,并且登录后跳转到main.html }
记住我功能
登录页面提供了记住我功能,此功能只需要往登录时提交一个remeber-me的参数,值可以是 on 、yes 、1 、 true,就会记住当前登录用户的token到cookie中。http.rememberMe().rememberMeParameter("remeber-me"),
使用这个配置可以定制参数名。而在登出时,会清除记住我功能的cookie。
"username":$("#userName").val(),
"password":$("#userPass").val(),
"remeber-me": "on|yes|1|true"
拦截策略
antMachers()方法设置路径匹配,可以用两个星号代表多层路径,一个星号代表一个或多个字符,问号代表一个字符。然后配置对应的安全策略:
permitAll()所有人都可以访问。denyAll()所有人都不能访问。 anonymous()只有未登录的人可以访问,已经登录的无法访问。
hasAuthority、hasRole这些是配置需要有对应的权限或者角色才能访问。 其中,角色就是对应一个ROLE_角色名 这样的一个资源。
另外的两个配置对象中,AuthenticationManagerBuilder配置认证策略,WebSecurity配置补充的Web请求策略
关于csrf
csrf全称是Cross—Site Request Forgery 跨站点请求伪造。这是一种安全攻击手段,简单来说,就是黑客可以利用存在客户端的信息来伪造成正常客户,进行攻击。例如你访问网站A,登录后,未退出又打开一个tab页访问网站B,这时候网站B
就可以利用保存在浏览器中的sessionId伪造成你的身份访问网站A。
我们在示例中是使用http.csrf().disable()方法简单的关闭了CSRF检查。而其实Spring Security针对CSRF是有一套专门的检查机制的。他的思想就是在后台的session中加入一个csrf的token值,然后向后端发送请求时,对于GET、HEAD、
TRACE、OPTIONS以外的请求,例如POST、PUT、DELETE等,会要求带上这个token值进行比对。
当我们打开csrf的检查,再访问默认的登录页时,可以看到在页面的登录form表单中,是有一个name为csrf的隐藏字段的,这个就是csrf的token。例如我们在freemarker的模板语言中可以使用添加这个参数。
而在查看Spring Security后台,有一个CsrfFilter专门负责对Csrf参数进行检查。他会调用HttpSessionCsrfTokenRepository生成一个CsrfToken,并将值保存到Session中。

浙公网安备 33010602011771号