一般的系统在权限设计上,都会分为角色、权限(RDBC),复杂一点的可能会有用户组、组织之类的概念。
用户的权限是写死的,对应于后台的接口或者资源,是没办法改变的,一般不对用户开放修改权限。
管理员用户可以通过给角色分配权限的方式,来实现访问控制。
所以当我们写过滤器,或者用一些安全框架时(比如 Shiro,Spring Security),也需要将可变的 “角色”,转化为不可变的 “权限”,注入到框架中。
具体的可以看我之前写的一篇(Spring Security 整合 jwt 完整版):https://blog.csdn.net/qq_37855749/article/details/111300906
注入当前用户的权限后,就需要进行访问控制了。
常见的做法有
1、路径比对
之前有个项目用过一次,定义一个过滤器,添加到 security 的过滤链中,在这个过滤器中做这么一件事:
分析当前访问路径所需要的权限,检查当前用户是否具有该权限,做一个对比,根据对比结果来决定当前用户是否可以访问该资源。
这种做法的好处是代码的入侵性不高,不需要再每个接口上加注解。但相对来说,显得不那么直观,可读性比较差,所以这次换个方法。
2、使用注解的方式
SpringSecurity 使用注解来控制访问时,需要提前开启这个功能。
在配置类上加上注解
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
在接口中如此使用
/**
* 条件查询
*/
@PreAuthorize("hasAuthority('IMPORT:SELECT')")
@ApiOperation(value = "查询")
@GetMapping("/list")
public R<Page<Task>> list(TaskDto taskDto){
//测试阶段,随机生成任务
Random random = new Random();
//todo
int i = random.nextInt(4);
if(i == 2) {
metroServerAdapterService.reloadShelveTask();
}
Page<Task> list = taskService.list(taskDto);
return R.ok(list);
}
hasAuthority 可以替换成 hasRole,虽然可以达到相同的目的,但是在使用的方法上还是有些不同的。
hasRole 要求内容必须以 “ROLE_” 开头,也是官方推荐的命名方式,否则没有效果。但是 hasAuthority 没有限制,数据库中怎样写的,代码里就怎么写。
同样的功能的注解为什么要有两个名字呢。或许这么做可能在语义上比较清晰明确一点,将角色与权限这两个概念稍加区分。
仔细想一下,确实有些小型的系统或许压根就不需要权限,只有给用户分配角色,没有给角色分配权限这一过程。这样的话,角色也是不可变的,就可以根据角色来做访问控制了。
但考虑通用性,个人觉得用 hasAuthority 就可以了。