Spring Security Wildcard Permissions

背景介绍


Shiro的Wildcard Permissions机制非常不错,具有很高的灵活性,奈何项目使用Spring Security,为了能支持更丰富的权限控制,所以就参考Shiro在Spring Security中实现 Wildcard Permissions。

实现方式


最开始想用注解+AOP的方式实现,Google之后发现Spring Security提供自定义@PostAuthorize("hasPermission()")的方法,只需实现PermissionEvaluator接口重写hasPermission方法即可,下面贴出实现代码

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class CustomPermissionEvaluator implements PermissionEvaluator {

public static final String LOGICAL_AND = "AND";

public static final String LOGICAL_OR = "OR";

@Override
public boolean hasPermission(Authentication authentication, Object logical,
Object permissions) {
if (null == permissions) {
return false;
}
if (SecurityUtils.hasAllPermission()) {
return true;
}
String permStr = permissions.toString().toLowerCase();
if (StringUtils.isBlank(permStr)) {
return false;
}
List<List<String>> allPermissionParts = SecurityUtils.getAllPermissionParts();
if (allPermissionParts.isEmpty()) {
return false;
}
List<List<String>> permissionParts = new ArrayList<>();
for (String perm : permStr.split(SecurityUtils.SUBPART_DIVIDER_TOKEN)) {
List<String> parts = new ArrayList<>();
for (String part : perm.split(SecurityUtils.PART_DIVIDER_TOKEN)) {
parts.add(part);
}
permissionParts.add(parts);
}
boolean result = false;
for (List<String> otherPart : permissionParts) {
boolean compare = false;
for (List<String> permissionPart : allPermissionParts) {
if (permissionPart.size() <= otherPart.size()) {
if (SecurityUtils.comparePermissionPart(permissionPart, otherPart)) {
compare = true;
}
}
}
if (compare && logical.equals(LOGICAL_OR)) {
return true;
}
if (!compare && logical.equals(LOGICAL_AND)) {
return false;
}
result = compare;
}
return result;
}

@Override
public boolean hasPermission(Authentication authentication, Serializable targetId,
String targetType, Object permission) {
return false;
}

}

权限判断通用操作工具类

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
public class SecurityUtils {

public static final String WILDCARD_TOKEN = "*";

public static final String PART_DIVIDER_TOKEN = ":";

public static final String SUBPART_DIVIDER_TOKEN = ",";

public static final String DEFAULT_ROLE_PREFIX = "ROLE_";

public static final String DEFAULT_ACCOUNT_TYPE_PREFIX = "ACT_";

public static final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(8);

public static boolean isLogin() {
if (null != SecurityContextHolder.getContext().getAuthentication()) {
boolean isAuthenticated = SecurityContextHolder.getContext().getAuthentication()
.isAuthenticated();
boolean isAnonymous = SecurityContextHolder.getContext()
.getAuthentication() instanceof AnonymousAuthenticationToken;
if (!isAnonymous) {
return isAuthenticated;
}
}
return false;
}

public static long getUserId() {
return getLoginDetail().getUserId();
}

public static List<GrantedAuthority> getAllAuthorities() {
List<GrantedAuthority> grantedAuthorities = (List<GrantedAuthority>) SecurityContextHolder
.getContext().getAuthentication().getAuthorities();
return grantedAuthorities;
}

public static boolean hasRole(String roleName) {
List<GrantedAuthority> grantedAuthorities = getAllAuthorities();
for (GrantedAuthority grantedAuthority : grantedAuthorities) {
if (grantedAuthority.getAuthority().equals(DEFAULT_ROLE_PREFIX + roleName)) {
return true;
}
}
return false;
}

private static UserLoginDetail getLoginDetail() {
return (UserLoginDetail) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
}

public static String getUserName() {
return getLoginDetail().getUsername();
}

// 权限比较 source是否包含target
public static boolean comparePermission(String source, String target) {
List<String> sourcePart = new ArrayList<>();
for (String part : source.toLowerCase().split(PART_DIVIDER_TOKEN)) {
sourcePart.add(part);
}
List<String> targetPart = new ArrayList<>();
for (String part : target.toLowerCase().split(PART_DIVIDER_TOKEN)) {
targetPart.add(part);
}
if (sourcePart.size() <= targetPart.size()) {
if (comparePermissionPart(sourcePart, targetPart)) {
return true;
}
}
return false;
}

public static boolean comparePermissionPart(List<String> permissionPart,
List<String> otherPart) {
for (int i = 0; i < permissionPart.size(); i++) {
if (!permissionPart.get(i).contains(SecurityUtils.WILDCARD_TOKEN) &&
!permissionPart.get(i).contains(otherPart.get(i))) {
return false;
}
}
return true;
}

public static boolean hasAllPermission() {
Collection<? extends GrantedAuthority> authorityList = getAllAuthorities();
for (GrantedAuthority grantedAuthority : authorityList) {
if (grantedAuthority.getAuthority().contains(SecurityUtils.WILDCARD_TOKEN)) {
return true;
}
}
return false;
}

public static boolean hasPermission(String permName) {
if (StringUtils.isBlank(permName)) {
return false;
}
if (SecurityUtils.hasAllPermission()) {
return true;
}
String permStr = permName.toString().toLowerCase();
if (StringUtils.isBlank(permStr)) {
return false;
}
List<List<String>> allPermissionParts = getAllPermissionParts();
if (allPermissionParts.isEmpty()) {
return false;
}
List<String> permPart = new ArrayList<>();
for (String part : permStr.split(PART_DIVIDER_TOKEN)) {
permPart.add(part);
}
boolean result = false;
for (List<String> permissionPart : allPermissionParts) {
if (permissionPart.get(0).equals(permPart.get(0))
&& permissionPart.size() <= permPart.size()) {
if (comparePermissionPart(permissionPart, permPart)) {
result = true;
}
}
}
return result;
}

// 获取当前用户所有权限
public static List<String> getAllPermissionName() {
List<List<String>> allPermissionParts = new ArrayList<>();
List<GrantedAuthority> authorityList = getAllAuthorities();
List<String> allPermission = authorityList.stream()
.map(x -> x.getAuthority())
.filter(s -> !s.startsWith(DEFAULT_ROLE_PREFIX) &&
!s.startsWith(DEFAULT_ACCOUNT_TYPE_PREFIX)) //过滤掉角色与账户类型
.collect(Collectors.toList());
return allPermission;
}

public static List<List<String>> getAllPermissionParts() {
List<List<String>> allPermissionParts = new ArrayList<>();
List<String> allPermission = getAllPermissionName();
for (String perm : allPermission) {
List<String> parts = new ArrayList<>();
for (String part : perm.split(PART_DIVIDER_TOKEN)) {
parts.add(part);
}
allPermissionParts.add(parts);
}
return allPermissionParts;
}

}

将CustomPermissionEvaluator注入给Spring Security即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) throws Exception {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator());
web.expressionHandler(handler);
}

public PermissionEvaluator permissionEvaluator() {
CustomPermissionEvaluator customPermissionEvaluator = new CustomPermissionEvaluator();
return customPermissionEvaluator;
}

}