【若依】12、权限中的概念梳理
Permission 是一个个具体的权限,例如可以删除一个用户、可以添加一个用户等等,这些都是操作权限。 多个权限合并在一起,就是一个角色。 Shiro 中,当要控制权限的时候,框架本身中是有两个概念的:
- Role
- Permission
但是在 Spring Security 中,反映到代码上,并无明确的 Role 和 Permission:
- 当前用户类,要实现 UserDetails 接口,在这个接口中,如果要返回用户角色/权限的话,调用 getAuthorities 方法。此时,getAuthorities 方法究竟是返回角色还是返回权限呢?理论上来说,这里其实返回角色还是返回权限,都是 OK 的。但是由于角色是权限的集合,所以我们可以拿着用户的角色,去查询用户的权限,然后这个地方返回权限会更合理一些。
- 例如创建一个用户的时候,给用户设置角色还是设置权限,最终的都是调用同步一个方法,只是角色里边多了一个
ROLE_
前缀而已。
官方🌰:Spring Security 的用户创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class SecurityConfig {
@Bean
UserDetailsService userDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
inMemoryUserDetailsManager.createUser(User.withUsername("yueyazhui").password("{noop}123")
// 给用户设置角色
.roles("admin")
// 给用户设置两个权限,可以添加/删除用户的权限
.authorities("system.user.add", "system.user.delete")
.build());
return inMemoryUserDetailsManager;
}
}
在这里,虽然我们可以为用户设置 role 或者 权限,但是,在代码层面,这两个的区别仅仅只是 role 的字符串额外带有一个 ROLE_
前缀。
当用户登录成功之后,我们去获取用户权限的时候,Spring Security 会自动根据权限和角色字符串的区别,给我们返回用户的权限(角色是不会返回的):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("hello")
public class HelloController {
@GetMapping
public void hello() {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for (GrantedAuthority authority : authorities) {
System.out.println("authority = " + authority);
// authority = system.user.add
// authority = system.user.delete
}
}
}
上面这个返回也是符合逻辑的。因为一般来说,权限才会控制用户具体的操作,角色一般是不控制用户具体的操作,角色仅仅只是用户权限的一个集合而已。
权限注解 @PreAuthorize("hasPermission('','system:user:add')")
中,里边的 hasPermission('','system:user:add')
实际上就是 SpEL 表达式,但是这个执行的方法没有指定这个方法是哪个对象中的方法,所以只有一种可能,这个方法是这里执行的 SpEL 的 RootObject 中的方法(SecurityExpressionRoot)。
system:user:*
表示具备对用户的所有权限.
在 Spring Security 中,注解中,判断权限和判断角色的逻辑是一模一样的,唯一的区别在于角色有一个 ROLE_
前缀,而权限没有这个前缀。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
public final boolean hasAuthority(String authority) {
return hasAnyAuthority(authority);
}
@Override
public final boolean hasAnyAuthority(String... authorities) {
return hasAnyAuthorityName(null, authorities);
}
@Override
public final boolean hasRole(String role) {
return hasAnyRole(role);
}
@Override
public final boolean hasAnyRole(String... roles) {
return hasAnyAuthorityName(this.defaultRolePrefix, roles);
}
/**
无论是判断角色还是判断权限,最终调用的都是 hasAnyAuthorityName,区别主要在于第一个参数,判断
权限的时候,第一个参数为 null,因为权限没有前缀;判断第二个角色的时候,第一个参数有前缀,前缀
为 ROLE_。这是这两个唯一的区别。
*/
private boolean hasAnyAuthorityName(String prefix, String... roles) {
Set<String> roleSet = getAuthoritySet();
for (String role : roles) {
String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
if (roleSet.contains(defaultedRole)) {
return true;
}
}
return false;
}
本文由作者按照
CC BY 4.0
进行授权