在学习这门课的时候,实现各种功能时进行了各种配置。我想将各种配置综合讲述一下。
首先自定义配置类,需要继承WebSecurityConfigurerAdapter
这个类。
在这个类里面做了一些默认配置。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
....
}
自定义密码的加密方式:
更改PasswordEncoder
的实现为BCryptPasswordEncoder
。
/**
* 配置用户密码加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(); // 这里使用 BCrypt (也可换别的)
}
注入Security工作图中的第二步–>用于验证JWT
在接口中我们通过AuthenticationManager的authenticate方法来进行用户认证,所以需要在SecurityConfig中配置把AuthenticationManager注入容器。
注入AuthenticationManager
,用它的方法进行认证
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
使用时:
authenticationManager.authenticate()
安全过滤器链配置方法HttpSecurity http
配置方法@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
super.configure(http);
使用了父类中一些默认配置。查看源代码
protected void configure(HttpSecurity http) throws Exception {
((HttpSecurity)((HttpSecurity)((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated()
.and())
.formLogin()
.and())
.httpBasic();
}
http.authorizeRequests().anyRequest().authenticated()
表示对任何请求都要进行权限认证
http.formLogin()
,加入了UsernamePasswordAuthenticationFilter
过滤器。
默认配置:
CSRF
攻击、XSS
攻击。关闭防止csrf
攻击
//前后端分离的项目需要关闭csrf
http.csrf().disable()
为什么要关闭防止
csrf
攻击?
CSRF
是指跨站请求伪造(Cross-site request forgery),是web常见的攻击之一。https://blog.csdn.net/freeking101/article/details/86537087
SpringSecurity
去防止CSRF
攻击的方式就是通过csrf_token
。后端会生成一个csrf_token
,前端发起请求的时候需要携带这个csrf_token
,后端会有过滤器进行校验,如果没有携带或者是伪造的就不允许访问。但是在前后端分离的项目中我们的认证信息其实是token,而token并不是存储中cookie中,并且需要前端代码去把token设置到请求头中才可以,所以
CSRF
攻击也就不用担心了。因此使用token是天然防止
csrf
攻击的。
不通过Session
获取SecurityContext
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
参考链接:
https://blog.csdn.net/qq_41865652/article/details/123685248
https://blog.csdn.net/Shair911/article/details/104181917/
http.authorizeRequests()
主要是对url
进行访问权限控制,通过这个方法来实现url
授权操作。
http.authorizeRequests()也支持连缀写法,总体公式为:
url 匹配规则. 权限控制方法
anyRequest()
,表示匹配所有的url
请求
http.authorizeRequests()
// 匹配所有的请求,并且所有请求都需要登录认证
.anyRequest().authenticated();
antMatcher(String regx)
,传递一个ant
表达式参数,表示匹配所有满足ant
表达式的请求
ant表达式中特殊字符解释
规则 | 解释说明 |
---|---|
? | 匹配一个字符 |
* | 匹配0个或多个字符 |
** | 匹配0个或多个目录 |
配置类代码示例:
http.authorizeRequests()
// 允许登录页面匿名访问
.antMatchers("/showLogin", "/errPage").anonymous()
// 所有的静态资源允许匿名访问
.antMatchers(
"/css/**",
"/js/**",
"/images/**",
"/fonts/**",
"/favicon.ico"
).anonymous()
// 其他所有的请求都需要登录认证
.anyRequest().authenticated();
antMatcher(HttpMethod.*, String regx)
,传递一个请求方法类型参数加ant表达式参数,表示匹配所有满足ant表达式的指定请求方式的url
请求方式的枚举类如下:
配置类代码示例:
http.authorizeRequests()
// 允许GET请求登录页面匿名访问
.antMatchers(HttpMethod.GET, "/showLogin", "/errPage").anonymous();
regexMatchers()
使用正则表达式进行匹配。和 antMatchers()主要的区别就是参数,antMatchers()参数是 ant 表达式,regexMatchers()参数是正则表达式。
演示所有以.js 结尾的文件都被放行。
http.authorizeRequests()
// 所有以.js 结尾的文件都被放行
.regexMatchers( ".+[.]js").permitAll()
两个参数时使用方式
无论是 antMatchers()还是 regexMatchers()都具有两个参数的方法,其中第一个参数都是 HttpMethod,表示请求方式,当设置了HttpMethod 后表示只有设定的特定的请求方式才执行对应的权限设置。
mvcMatchers()
适用于配置了 servletPath 的情况。
servletPath 就是所有的 URL 的统一前缀。在 SpringBoot 整合SpringMVC 的项目中可以在 application.properties 中添加下面内容设置 ServletPath
spring.mvc.servlet.path=/bjsxt
在 Spring Security 的配置类中配置.servletPath()是 mvcMatchers()返回值特有的方法,antMatchers()和 regexMatchers()没有这个方法。在 servletPath()中配置了 servletPath 后,mvcMatchers()直接写 SpringMVC 中@RequestMapping()中设置的路径即可。
http.authorizeRequests()
.mvcMatchers("demo").servletPath("/bjsxt").permitAll()
如果不习惯使用 mvcMatchers()也可以使用 antMatchers(),下面代码和上面代码是等效的
http.authorizeRequests()
.antMatchers( "/bjsxt/demo").permitAll()
方法名称 | 方法作用 |
---|---|
permitAll() |
表示所匹配的URL任何人都允许访问 |
anonymous() |
表示可以匿名访问匹配的URL。和permitAll() 效果类似,只是设置为anonymous() 的url会执行filterChain 中的filter |
denyAll() |
表示所匹配的URL都不允许被访问。 |
authenticated() |
表示所匹配的URL都需要被认证才能访问 |
rememberMe() |
允许通过remember-me登录的用户访问 |
access() |
SpringEl 表达式结果为true时可以访问 |
fullyAuthenticated() |
用户完全认证可以访问(非remember-me下自动登录) |
hasRole() |
如果有参数,参数表示角色,则其角色可以访问 |
hasAnyRole() |
如果有参数,参数表示角色,则其中任何一个角色可以访问 |
hasAuthority() |
如果有参数,参数表示权限,则其权限可以访问 |
hasAnyAuthority() |
如果有参数,参数表示权限,则其中任何一个权限可以访问 |
hasIpAddress() |
如果有参数,参数表示IP 地址,如果用户IP 和参数匹配,则可以访问 |
配置案例示例:
//任何用户都可以访问
http.authorizeRequests().antMatchers("/index").permitAll();
http.authorizeRequests().antMatchers("/index").access("permitAll");]
//任何用户都不能访问
http.authorizeRequests().antMatchers("/home").denyAll();
http.authorizeRequests().antMatchers("/home").access("denyAll");
//认证用户可以访问(除了匿名认证)
http.authorizeRequests().antMatchers("/admin").authenticated();
http.authorizeRequests().antMatchers("/admin").access("authenticated");
//认证用户可以访问(除了匿名认证,记住我)
http.authorizeRequests().antMatchers("/admin").fullyAuthenticated();
http.authorizeRequests().antMatchers("/admin").access("fullyAuthenticated");
//记住我的认证可以访问
http.authorizeRequests().antMatchers("/admin").rememberMe();
http.authorizeRequests().antMatchers("/admin").access("rememberMe");
//匿名用户可以访问
http.authorizeRequests().antMatchers("/admin").anonymous();
http.authorizeRequests().antMatchers("/admin").access("anonymous");
//是否有权限
http.authorizeRequests().antMatchers("/index").hasAuthority("user");
http.authorizeRequests().antMatchers("/index").access("hasAuthority('user')");
//是否有任意一个权限
http.authorizeRequests().antMatchers("/home").hasAnyAuthority("update", "delete", "insert");
http.authorizeRequests().antMatchers("/home").access("hasAnyAuthority('update','delete','insert')");
//spring security中的role并非是一个或多个权限的集合,而是权限的一种,通常以ROLE_开头
//role就是ROLE_开头的权限
//注意:hasRole、hasAnyRole里面的role不需要以ROLE_开头,否则会报异常
//注意:如果在access里面使用hasRole、hasAnyRole则ROLE_前缀可加,可不加
http.authorizeRequests().antMatchers("/index").hasRole("GUEST");
http.authorizeRequests().antMatchers("/index").access("hasRole('GUEST')");
http.authorizeRequests().antMatchers("/admin").hasAuthority("ROLE_GUEST");
http.authorizeRequests().antMatchers("/home").hasAnyRole("GUEST", "USER", "ADMIN");
http.authorizeRequests().antMatchers("/home").access("hasAnyRole('ROLE_GUEST','ROLE_USER','ROLE_ADMIN')");
先将获取过滤器
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; // 注入Jwt认证过滤器
然后配置到过滤器链中
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
//将jwtAuthenticationTokenFilter 过滤器放到UsernamePasswordAuthenticationFilter过滤器前。
addFilterBefore()
:将过滤器放到 **过滤器之前。
addFilter()
:将过滤器放到过滤器链最后。
addFilterAfter()
:将过滤器放到 **过滤器之后。
http.addFilterAfter(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
//将jwtAuthenticationTokenFilter 过滤器放到UsernamePasswordAuthenticationFilter过滤器后。
addFilterAt
:将过滤器放在**过滤的位置。并不是取代。
先获取异常处理器
@Autowired
AuthenticationEntryPoint authenticationEntryPoint; // 注入(自定义的 认证过程中 出现异常的处理方法)
@Autowired
AccessDeniedHandler accessDeniedHandler; // 注入(自定义 授权过程中 出现异常的处理方法)
然后进行配置。
/**
* 配置异常处理器
*/
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint) // 配置认证失败处理器
.accessDeniedHandler(accessDeniedHandler); // 配置授权失败处理器
取消默认的自带的表单登录配置
http.formLogin().disable();
配置演示
@SpringBootConfiguration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()//开启formLogin默认配置
.loginPage("/login/auth").permitAll()//请求时未登录跳转接口
.failureUrl("/login/fail")//用户密码错误跳转接口
.defaultSuccessUrl("/login/success",true)//登录成功跳转接口
.loginProcessingUrl("/login")//post登录接口,登录验证由系统实现
.usernameParameter("username") //要认证的用户参数名,默认username
.passwordParameter("password") //要认证的密码参数名,默认password
.and()
.logout()//配置注销
.logoutUrl("/logout")//注销接口
.logoutSuccessUrl("/login/logout").permitAll()//注销成功跳转接口
.deleteCookies("myCookie") //删除自定义的cookie
.and()
.csrf().disable(); //禁用csrf
}
}
使用formLogin()
就会添加如下过滤器
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
添加认证成功处理器和认证失败处理器
先获取认证成功处理器和认证失败处理器。
@Autowired
private AuthenticationSuccessHandler successHandler;
@Autowired
private AuthenticationFailureHandler failureHandler;
然后再进行配置
http.formLogin()
//配置认证成功处理器
.successHandler(successHandler)
//配置认证失败处理器
.failureHandler(failureHandler);
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启SecurityConfig 权限控制功能
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
AuthenticationEntryPoint authenticationEntryPoint;
@Autowired
AccessDeniedHandler accessDeniedHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//前后端分离的项目需要关闭csrf
.csrf().disable()
//不通过Session获取SecurityContext
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
// 对于登录接口 允许匿名访问
.antMatchers("/user/login").anonymous()
// 除上面外的所有请求全部都需要认证即可访问
.anyRequest().authenticated();
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint) // 配置认证失败处理器
.accessDeniedHandler(accessDeniedHandler); // 配置授权失败处理器
//关闭默认的注销功能
http.logout().disable();
//把token校验过滤器添加到过滤器链中
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 允许跨域
http.cors();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 配置用户密码加密方式
*/
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(); // 这里使用 BCrypt (也可换别的)
}
}