Spring Security 的权限分控制也是参考 RBAC 模型来的,由
用户、角色、权限等基础部分组成,然后再这个基础之上进行设计和开发而来的一套安全框架。
1. Security 实现授权的基本方式
我认为 Spring Security 的认证方式无非是三种如下所示:
我这里只是简单的测试一下前两种的认证方式,第三种很常用,但是比较复杂,下次再写
- 基于配置的对
url授权 - 基于注解的对方法级别的授权
- 动态的实现授权认证
a. 基于配置的对 url 授权
构建项目的过程自动忽略了,由于不需要从数据库中读取权限,所以本次不需要与数据库交互,采用简单的从内存中读取用户。
初始化环境:
用户三个:
admin 密码 admin 角色 test,admin
test 密码 test 角色 test
dev 密码 dev 角色 dev
资源url:
/admin/add
/admin/upodate
/test/add
/test/upodate
/dev/add
/dev/upodate
配置用户
// 密码器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
// 配置基础的用户三个
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("admin")).roles("test","admin")
.and()
.withUser("test").password(passwordEncoder().encode("test")).roles("test")
.and()
.withUser("dev").password(passwordEncoder().encode("dev")).roles("dev")
;
}
// 配置url的权限和授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 有 admin 角色的可以访问所有的 admin/ 开头的请求
.antMatchers("/admin/**").hasRole("admin")
// 有 test 角色的可以访问所有的 test/ 开头的请求
.mvcMatchers("/test/**").hasRole("test")
// 有 admin 或者 dev 角色的都可以访问所有的 dev/ 开头的请求
.antMatchers("/dev/**").hasAnyRole("admin","dev","test")
// 其他请求只要登录就可以访问
.anyRequest().authenticated()
.and()
// 开启表单登录和登陆成功后的url url默认方式是POST方式
.formLogin()
.successForwardUrl("/index")
;
}
admin controller
@RestController
@RequestMapping("/admin")
public class AdminController {
@GetMapping("/add")
public String add(){
return this.getClass()+"添加的方法";
}
@GetMapping("/update")
public String update(){
return this.getClass()+"更新的方法的方法";
}
}
test controller
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/add")
public String add(){
return this.getClass()+"添加的方法";
}
@GetMapping("/update")
public String update(){
return this.getClass()+"更新的方法的方法";
}
}
dev controller
@RestController
@RequestMapping("/dev")
public class DevController {
@GetMapping("/add")
public String add(){
return this.getClass()+"添加的方法";
}
@GetMapping("/update")
public String update(){
return this.getClass()+"更新的方法的方法";
}
}
登录成功后的index请求
/**
* @author logic
*/
@RestController
public class IndexController {
@PostMapping("/index")
public String index(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication.getName()+"登录成功";
}
}
预测结果:
- admin 可以访问所有的url 因为 admin 有
admin、test两个角色,所以admin/**、和test/**的所有请求都可以访问,然后dev/**配置了只要有admin或者devtest角色的都可以访问,所以admin用户可以访问多有的url - test 用户可以访问
test/**和dev/**的所有url - dev 用户只能访问
dev/** - 其他未分配的url只要登录即可访问,配置过的url需要对应的权限才能访问
结果截图:
admin 用户的截图




test 用户:




dev用户的截图




总结:通过配置的方式分配权限主要是使用这几个方法,
antMatchers()、mvcMatchers(),这两个方法定义路径的,hasRole()、hasAnyRole()这两个方法设置权限。只要一一对应即可访问。
还有一对方法hasAuthority()、hasAnyAuthority通过判断用户的GrantedAuthority来进行访问控制,底层跟hasAnyRole()差不多,我这里就不测试了。
权限开放的方法是permitAll(),.antMatchers("/**").permitAll()就表示所有的请求都可以通过,不需要验证
通过配置的方式一般是不用的,配置一般只配置一些静态的文件资源
b. 基于注解的对方法级别的授权
基于注解的方式有几个前提条件:
- 注释掉配置文件中的路由配置(url的权限配置)
- 开启全局的注解
@EnableGlobalMethodSecurity- 选择使用的参数,共支持
prePostEnabled,securedEnabled,jsr250Enabled,proxyTargetClass四种参数
- 使用
prePostEnabled
使用prePostEnabled只用在注解上面开启prePostEnabled即可如:@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//密码器
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("admin")).roles("test","admin")
.and()
.withUser("test").password(passwordEncoder().encode("test")).roles("test")
.and()
.withUser("dev").password(passwordEncoder().encode("dev")).roles("dev")
;
}
// 配置url的权限和授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.successForwardUrl("/index")
;
}
}
- 使用
prePostEnabled的话涉及到了四个注解@PreAuthorize、@PostAuthorize、@PreFilter、@PostFilter
-
PerAuthorize 它的作用就是在调用标记的方法之前,通过表达式来判定是否有权限访问。常用的方法有
- 基于角色的授权方式如:
@PreAuthorize("hasAnyRole('admin')"),表示标记的方法拥有admin角色才可以访问 - 基于
UserDetails的表达式,例如@PreAuthorize("hasAnyRole('admin') and principal.username.startsWith('adm')")必须有admin角色和用户名必须adm开头 - 基于对入参的 SpEL 表达式处理方法入参,例如:
@PreAuthorize("#name.equals(principal.username)")表示请求参数name必须与登录的用户命相同才能访问
- 基于角色的授权方式如:
-
PostAuthorize 它的作用跟 PerAuthorize 一样,只不过是在调用目标方法之后执行,如果方法没有返回值,那么相当于没有权限。
-
@PreFilter 它的验证过程发生在接口接收参数之前,对入参进行过滤,并且入参必须为
java.utile.Collection,你入参是一个集合,那么他就可以对这个集合里面的数据通过规则进行过滤。 -
@PreFilter 它的验证过程发生在接口处理好数据进行返回的时候,可以对返回的结果进行过滤。
测试:
@RestController @RequestMapping("/admin") public class AdminController { @GetMapping("/add") @PreAuthorize("hasAnyRole('admin') and principal.username.startsWith('adm')") public String add(){ return this.getClass()+"添加的方法"; } @PreAuthorize("#name.equals(principal.username)") @GetMapping("/update") public String update(String name){ return this.getClass()+"更新的方法的方法"; } @PreFilter(value = "filterObject.contains(principal.username)",filterTarget = "names") @GetMapping("/del") public String del(@RequestParam(value = "names") List<String> names){ System.out.println(names); return this.getClass()+"删除方法执行成功"; } }
预测结果:
1.用户admin可以访问 /admin/add
2.所有用户访问/admin/update?name=? 携带参数与登录用户名相同即可访问
3.用户dev,test无法访问/admin/add
测试:
1. admin




2. test 用户




总结:spring security 的认证方式有好几种,通常都是从数据库中读取角色来分配权限的,像配置和注解一般不使用,就像注解系统默认是关闭的,通过javaConfig来配置的一般只是一些静态的文件,但是我们现在的项目一般都是前后端分离和分布式的,一般也用不上配置,所以这些只用了解即可,所以一些测试我也没有做的那么全。
本文介绍Spring Security中的权限管理实现方式,包括基于配置的URL授权和基于注解的方法级授权。通过对不同用户角色的配置和注解的应用,展示了如何对特定资源进行细粒度的访问控制。
2253

被折叠的 条评论
为什么被折叠?



