一、授权流程
用户登录成功后会将用户信息保存在Authencation对象中,Authencation接口中有一个getAuthorities()方法返回的是用户的权限
Collection<? extends GrantedAuthority> getAuthorities();
现有系统可以基于角色做权限管理也可以使用资源(权限字符串)做权限管理,这里的GrantedAuthority是角色还是资源呢?
- 如果 业务是基于角色做的权限管理,即用户->角色->资源,那么返回的是用户的角色
- 如果业务是基于资源(权限)做的权限管理,即用户->权限->资源,返回的是用户的权限
- 如果基于角色+权限做的权限管理,即用户->角色->权限->资源,返回的是用户的权限
security在角色和权限的处理方式上基本一样的,唯一区别就是很多时候会自动给角色增加一个ROLE_前缀,而权限不会添加
二、权限管理策略
1、基于URL做权限管理(过滤器技术实现)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//创建内存数据源
public UserDetailsService userDetailsService(){
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
//admin用户 具有ADMIN 和 USER角色
inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("{noop}123").roles("ADMIN","USER").build());
//user用户 具有USER角色
inMemoryUserDetailsManager.createUser(User.withUsername("user").password("{noop}123").roles("USER").build());
//info用户具有READ_INFO权限操作
inMemoryUserDetailsManager.createUser(User.withUsername("info").password("{noop}123").authorities("READ_INFO").build());
return inMemoryUserDetailsManager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
//访问/admin必须有ADMIN角色
.mvcMatchers("/admin").hasRole("ADMIN")
//访问/user需要USER角色或者ADMIN角色
.mvcMatchers("/user").hasAnyRole("ADMIN","USER")
//访问/info必须有READ_INFO权限
.mvcMatchers("/info").hasAuthority("READ_INFO")
.anyRequest().authenticated()
.and().formLogin()
.and().csrf().disable();
}
}
备注1:上面的hasRole()、hasAuthority()称为权限表达式,类如下
备注2:mvcMatchers、antMatchers、regexMatchers区别是?
1、mvcMatchers是在antMatchers之后增加的,两个都可以传递请求方式以及多个路径,如下
.mvcMatchers(HttpMethod.GET,"/admin","/test").hasRole("ADMIN")
.antMatchers(HttpMethod.GET,"/admin","/test").hasRole("ADMIN")
2、mvcMatchers相对antMatchers更加强大一些,比如mvcMatchers("/admin")可以匹配“/admin"还可以匹配"/admin/" 、"/admin/a"、"/admin.html",但是.antMatchers("/admin")只能匹配"/admin"
3、regexMatchers则是可以通过正在表达式匹配
2、基于方法策略权限管理(基于AOP技术实现)
基于方法的权限管理是基于aop技术实现的,security中通过MethodSecurityInterceptor提供相关实现,不同在于FilterSecurityInterceptor只是请求前置进行处理,而MethodSecurityInterceptor除了前置请求还可以进行后置请求,前置是在请求之前判断是否具有相应的权限,后置则是对方法的执行结果进行二次过滤,前置和后置分别对应了不同的实现类,
/**
* EnableGlobalMethodSecurity是开启全局方法的权限注解
* prePostEnabled开启security提供的四个权限注解,这四个注解支持上面的权限表达式
* @PostFilter在目标方法执行之后对方法的返回结果进行过滤
* @PostAuthorize在目标方法执行之后进行权限校验
* @PreAuthorize在目标方法执行之前进行校验
* @PreFilter在目标方法执行之前对参数进行过滤
* securedEnabled开启security提供的@secured,只支持角色,不支持权限表达式
* @secured访问目标方法必须具备相应的角色
* jsr250Enabled开启JSR-250提供的三个权限注解,同样只支持角色不支持权限表达式
* @DenyAll拒绝所有访问
* @PermitAll允许所有访问
* @RolesAllowed访问目标方法必须具备相应的角色
*
*这些基于方法的权限注解,一般来说只要设置prePostEnabled=true就够了
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true,jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//创建内存数据源
@Bean
public UserDetailsService userDetailsService(){
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
//admin用户 具有ADMIN 和 USER角色
inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("{noop}123").roles("ADMIN","USER").build());
//user用户 具有USER角色
inMemoryUserDetailsManager.createUser(User.withUsername("user").password("{noop}123").roles("USER").build());
//info用户具有READ_INFO权限操作
inMemoryUserDetailsManager.createUser(User.withUsername("info").password("{noop}123").authorities("READ_INFO").build());
return inMemoryUserDetailsManager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and().formLogin()
.and().csrf().disable();
}
}
使用
@RestController
@RequestMapping("/demo")
public class DemoController {
/**
*可以使用权限表达式以及and or
*除了角色还可以使用权限hasAuthority
*/
@PreAuthorize("hasRole('ADMIN') and authentication.name=='admin'")
@GetMapping("/user")
public String user(){
return "user";
}
/**
* 传的参数如果和登录用户的账号相同才能访问
*/
@PreAuthorize("authentication.name==#username")
@GetMapping("/name")
public String name(String username){
return "name";
}
/**
* 请求方法前对参数过滤 参数必须是数组、集合
*/
@PreFilter(value = "filterTarget.id%2!=0",filterTarget = "users")
@GetMapping("/users")
public String name(@RequestBody List<User> users){
return "user";
}
/**
* 返回指定的对象
*/
@PostAuthorize("returnObject.id==1")
@GetMapping("/userId")
public String userId(@RequestBody List<User> users){
return "userId";
}
/**
* 过滤方法的返回值 返回值是数组或者集合
*/
@PostFilter("filterTarget.id%2==0")
@GetMapping("/all")
public String all(@RequestBody List<User> users){
return "all";
}
/**
* 只能判断角色,可以是多个 ,具有其中一个即可
*/
@Secured("{ROLE_USER,ROLE_ADMIN}")
@GetMapping("/Secured")
public String secured(@RequestBody List<User> users){
return "Secured";
}
/**
* 放行所有
*/
@PermitAll
@GetMapping("/PermitAll")
public String permitAll(@RequestBody List<User> users){
return "PermitAll";
}
/**
* 拒绝所有请求
*/
@DenyAll
@GetMapping("/denyall")
public String denyAll(){
return "denyall";
}
/**
* 具有其中一个角色即可
*/
@RolesAllowed("{ROLE_ADMIN,ROLE_USER}")
@GetMapping("/rolseAll")
public String rolseAll(){
return "rolseAll";
}
}
版权归原作者 程序三两行 所有, 如有侵权,请联系我们删除。