概念
Spring-security是一个认证+鉴权的支持库,通过一系列filter来处理用户的认证,以及对后端接口权限的控制。
配置
image.png截图里都是针对HttpSecurity请求的配置
.authorizeRequests()
.anyRequest().authenticated()
.and()
- 对http请求的处理,所有请求都需要认证。
- 可以配置regexMatchers(),antMatcher() 等方法对请求进行精准的匹配。
.formLogin()
.loginPage("/auth/login").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.loginProcessingUrl("/auth/doAuth")
.defaultSuccessUrl("/auth/index")
.failureForwardUrl("/auth/failed")
.and()
登录页面的处理
- loginPage 登录页面,当没有权限访问的时候跳转到此页面,permitAll()指定这个页面无需鉴权。
- usernameParameter,passwordParameter 指定登录页面的参数名称。
- loginProcessingUrl 登录请求的后台 url
- defaultSuccessUrl 登录成功后的跳转页面
- failureForwardUrl 登录失败后的跳转页面
看到这里,都是登录的配置,但是具体的认证操作是在哪里处理的呢?
image.png- 一个AuthenticationManagerBuilder包含多个AuthenticationProvider
- 一个AuthenticationManagerBuilder包含一个userDetailsService
具体的一个AuthenticationProvider:
image.png
- suports方法,标识这个provider所能处理的认证凭证。
- authenticate方法,具体的认证逻辑,返回一个Authentication的子类,比如这里返回UsernamePasswordAuthenticationToken,里边包括用户名密码以及权限信息。
具体的UserDetailsService:
image.png
- AuthenticationProvider方法内部会使用UserDetailsService来查询用户的具体信息,用这个信息来认证。
认证失败如何处理:
image.png
GrantedAuthorityDefaults
我们用注解来验证权限的时候
@GetMapping("/delUser")
@PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_DELETE')")
public String delete() {
return "具有【用户删除】权限";
}
验证的时候,通过查看 hasAnyRole源码,我们发现系统在做校验是默认会加一个角色前缀:private String defaultRolePrefix = "ROLE_";
image.png
如果不需要,可以在 WebSecurityConfig 中通过配置去掉这个默认前缀。
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
// Remove the ROLE_ prefix
return new GrantedAuthorityDefaults("");
}
PasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {
// 密码加密方式
return new BCryptPasswordEncoder();
}
默认对密码字段都需要配置解密函数,同时要保证前台传来的是加密后的字符串。
注解方式鉴权
一、注解式方法级安全开启
需要在WebSecuirtyConfig添加配置:
@Configuration
@EnableWebSecurity //启用Spring Security.
////会拦截注解了@PreAuthrize注解的配置.
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
}
二、允许的注解
这里主要@PreAuthorize, @PostAuthorize, @Secured这三个注解可以使用。
- @Secured,当@EnableGlobalMethodSecurity(securedEnabled=true)的时候,@Secured可以使用:
@GetMapping("/helloUser")
@Secured({"ROLE_normal","ROLE_admin"})
public String helloUser() {
return "hello,user";
}
说明:拥有normal或者admin角色的用户都可以方法helloUser()方法。另外需要注意的是这里匹配的字符串需要添加前缀“ROLE_“。
如果我们要求,只有同时拥有admin & noremal的用户才能方法helloUser()方法,这时候@Secured就无能为力了。
- @PreAuthorize
Spring的 @PreAuthorize/@PostAuthorize 注解更适合方法级的安全,也支持Spring 表达式语言,提供了基于表达式的访问控制。
当@EnableGlobalMethodSecurity(prePostEnabled=true)的时候,@PreAuthorize可以使用:
@GetMapping("/helloUser")
@PreAuthorize("hasAnyRole('normal','admin')")
public String helloUser() {
return "hello,user";
}
说明:拥有normal或者admin角色的用户都可以方法helloUser()方法。
此时如果我们要求用户必须同时拥有normal和admin的话,那么可以这么编码: @PreAuthorize("hasRole('normal') AND hasRole('admin')")
- @PostAuthorize
@PostAuthorize 注解使用并不多,在方法执行后再进行权限验证,适合验证带有返回值的权限,Spring EL 提供 返回对象能够在表达式语言中获取返回的对象returnObject。
当@EnableGlobalMethodSecurity(prePostEnabled=true)的时候,@PostAuthorize可以使用:
@GetMapping("/helloUser")
@PostAuthorize(" returnObject!=null && returnObject.username == authentication.name")
public User helloUser() {
Object pricipal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user;
if("anonymousUser".equals(pricipal)) {
user = null;
}else {
user = (User) pricipal;
}
return user;
}
这三个最常用也就是@PreAuthorize这个注解了,在使用中主要是配合Spring EL表达式。
网友评论