权限校验

权限资源容器

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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
import com.banksteel.openerp.commons.constants.AuthorizationConstants;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* 〈一句话功能简述〉<br>
* Description: 权限资源注解
*
* @author hillchen
* @create 2019/6/25 20:54
*/
public class PermissionContext {
private static Logger logger = LoggerFactory.getLogger(PermissionContext.class);
/**
* url直连请求集
*/
private static Set<String> URL_REQS = new ConcurrentHashSet<>();
/**
* 所有请求和请求对象map
*/
private static Map<String,PermissionRequest> URL_METHOD_PREQUESTS = new ConcurrentHashMap<>();
/**
* command请求和请求对象map
*/
private static Map<String,PermissionRequest> COMMAND_PREQUESTS = new ConcurrentHashMap<>();

private static String API_PATH = "/api";

private static final String PATH_SLIPT="/";

/**
* 处理controller bean,将controller类上定义的PermissionSource加载到上下文中
* @param beanClazz
*/
public static void processBeanClass(Class beanClazz){
// 所有的controller bean 都有进行扩展
String basePath = getBasePath(beanClazz);
Method[] methods = beanClazz.getMethods();

for(Method method : methods){
handleControllerMethod(method, basePath);
}
}


/**
* 获取controller的基础地址
*/
private static String getBasePath(Class beanClazz){
if (beanClazz.isAnnotationPresent(RequestMapping.class)){
RequestMapping requestMapping = (RequestMapping) beanClazz.getAnnotation(RequestMapping.class);
String[] vals = requestMapping.value();

if (vals != null && vals.length != 0){
return vals[0];
}
}

return "";
}


/**
* 处理controller 的mapping方法,将controller的mapping方法上定义的PermissionSource加载到上下文中
* @param method
* @param basePath
*/
private static void handleControllerMethod(Method method,String basePath){
// 该方法为mapper方法
if (method.isAnnotationPresent(RequestMapping.class)){
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
PermissionSource permissionSource = getMethodPermissionSource(method);
handleControllerMethod(requestMapping, permissionSource, basePath,method);
}
}

/**
* 获取方法上定义的PermissionSource注解
* @param method
* @return
*/
private static PermissionSource getMethodPermissionSource(Method method){
if (method.isAnnotationPresent(PermissionSource.class)){
return method.getAnnotation(PermissionSource.class);
}
return null;
}

/**
* 将controller的mapping方法上定义的PermissionSource解析成PermissionRequest对象,加载到上下文中
* @param requestMapping
* @param permissionSource
* @param basePath
* @param method
*/
private static void handleControllerMethod(RequestMapping requestMapping, PermissionSource permissionSource,String basePath,Method method){
String relativePath = getRelativePath(requestMapping);

if (permissionSource == null){
// 为配置资源权限注解,则默认直接配置为通过url访问
initUrlRequest(basePath,relativePath,method,PermissionLevel.COMMAND_PERMISSION,requestMapping);
}else{
if (Objects.equals(RequestType.URL,permissionSource.type())){
initUrlRequest(basePath,relativePath,method,permissionSource.level(),requestMapping);
}else {
initCommandRequest(basePath,relativePath,method,permissionSource.level(),requestMapping,permissionSource.command());
}
}
}

/**
* 初始化url方式暴露的请求资源,并注入到上下文中
* @param basePath
* @param relativePath
* @param method
* @param level
* @param requestMapping
*/
private static void initUrlRequest(String basePath,String relativePath,Method method,
PermissionLevel level,RequestMapping requestMapping){
RequestMethod requestMethod = getRequestMethod(requestMapping,null);
PermissionRequest permissionRequest = buildUrlRequest(basePath, relativePath, method, level, requestMethod);
URL_METHOD_PREQUESTS.put(permissionRequest.getMethodRequestPath(),permissionRequest);
URL_REQS.add(permissionRequest.getMethodRequestPath());
}

/**
* 初始化command方式暴露的请求资源,并注入到上下文中
* @param basePath
* @param relativePath
* @param method
* @param level
* @param requestMapping
* @param command
*/
private static void initCommandRequest(String basePath,String relativePath,Method method,
PermissionLevel level,RequestMapping requestMapping,String command){
RequestMethod requestMethod = getRequestMethod(requestMapping,RequestMethod.POST);
PermissionRequest permissionRequest = buildCommandRequest(basePath, relativePath, method, level, requestMethod,command);

if (COMMAND_PREQUESTS.containsKey(command)){
PermissionRequest oldPermissionRequest = COMMAND_PREQUESTS.get(command);
throw new PermissionInitException(String.format("command[%s] 已经被请求%s定义,不可再请求%s上重复使用。",command
,oldPermissionRequest.getRequestPath(),permissionRequest.getRequestPath()));
}

URL_METHOD_PREQUESTS.put(permissionRequest.getMethodRequestPath(),permissionRequest);
COMMAND_PREQUESTS.put(command,permissionRequest);
}

/**
* 构建请求资源
* @param basePath
* @param relativePath
* @param method
* @param level
* @param requestMethod
* @return
*/
private static PermissionRequest buildUrlRequest(String basePath,String relativePath,Method method,
PermissionLevel level,RequestMethod requestMethod){
return buildRequest(basePath,relativePath,method,level,requestMethod,"",RequestType.URL);
}

/**
* 构建请求资源
* @param basePath
* @param relativePath
* @param method
* @param level
* @param requestMethod
* @param command
* @return
*/
private static PermissionRequest buildCommandRequest(String basePath,String relativePath,Method method,
PermissionLevel level,RequestMethod requestMethod,String command){
return buildRequest(basePath,relativePath,method,level,requestMethod,command,RequestType.COMMAND);
}

/**
* 构建请求资源
* @param basePath
* @param relativePath
* @param method
* @param level
* @param requestMethod
* @param command
* @param requestType
* @return
*/
private static PermissionRequest buildRequest(String basePath,String relativePath,Method method,PermissionLevel level,
RequestMethod requestMethod,String command,RequestType requestType){
if (StringUtils.isNotBlank(basePath) && StringUtils.endsWith(basePath,PATH_SLIPT)){
basePath = StringUtils.substring(basePath,0,basePath.length() - 1);
}
if (StringUtils.isNotBlank(relativePath) && !StringUtils.startsWith(relativePath,PATH_SLIPT)){
relativePath = PATH_SLIPT + relativePath;
}
String reqPath = basePath + relativePath;
String methodReqPath = createMethodReqPath(requestMethod, reqPath);

PermissionRequest request = new PermissionRequest();
request.setRequestMethod(requestMethod);
request.setBasePath(basePath);
request.setRelativePath(relativePath);
request.setRequestPath(reqPath);
request.setMethodRequestPath(methodReqPath);
request.setRequestType(requestType);
request.setCommand(command);
request.setLevel(level);
request.setClazz(method.getDeclaringClass());
request.setMethodName(method.getName());

return request;
}

/**
* 获取请求相对地址,本扩张器暂时对多映射地址请求不处理
* @param requestMapping
* @return
*/
private static String getRelativePath(RequestMapping requestMapping) {
String[] relativePaths = requestMapping.value();
if (relativePaths == null || relativePaths.length == 0){
return "";
}
if (relativePaths.length > 1){
logger.warn("暂时不支持对多映射");
}
return relativePaths[0];
}

private static RequestMethod getRequestMethod(RequestMapping requestMapping,RequestMethod defMethod) {
RequestMethod[] methods = requestMapping.method();
if (methods == null || methods.length == 0){
return defMethod;
}
if (methods.length > 1){
logger.warn("暂时不支持对多请求Method");
}
return methods[0];
}

/**
* 拼装MethodReqPath
* @param method
* @param reqPath
* @return
*/
public static String createMethodReqPath(RequestMethod method, String reqPath ){
if (method != null){
return method.toString() + "," + reqPath;
}else {
return reqPath;
}
}

/**
* 拼装MethodReqPath
* @param method
* @param reqPath
* @return
*/
public static String createMethodReqPath(String method, String reqPath ){
return method.toUpperCase() + "," + reqPath;
}

/**
* 通过api请求地址和请求方式,判断是否为通过http暴露的请求资源
* @param apiReq
* @param method
* @return
*/
public static boolean checkIsUrlReq(String apiReq,String method){
if (StringUtils.isBlank(apiReq)){
return false;
}
if (URL_REQS.contains(apiReq)){
return true;
}

String methodReqPath = createMethodReqPath(method,apiReq);
PermissionRequest permissionRequest = URL_METHOD_PREQUESTS.get(methodReqPath);
if (permissionRequest == null) {
throw new PermissionRequestException(String.format("请求资源[%s]配置未找到",methodReqPath));
}


return Objects.equals(RequestType.URL, permissionRequest.getRequestType());
}

/**
* 检查请求是否合法
* @param requestUrl
* @return
*/
public static boolean checkIsLegalReq(String requestUrl){
boolean fls = requestUrl.equals("/finance/api");
boolean ils = requestUrl.equals("/inventory/api");
boolean pls = requestUrl.equals("/purchase/api");
boolean sls = requestUrl.equals("/sale/api");
boolean tls = requestUrl.equals("/template/api");
boolean rls = requestUrl.equals("/process/api");
boolean cls = requestUrl.equals("/customer/api");
boolean ps = requestUrl.equals("/ps/api");
return ps || cls || rls || tls || pls || ils|| fls ||sls||requestUrl.equals("/api")||requestUrl.equals("/data");
}

/**
* 通过command配置集合重置上下文中的资源权限级别
* @param commands
* @param level
*/
public static void resetCommand(Collection<String> commands, PermissionLevel level){
if (CollectionUtils.isNotEmpty(commands) ){
for (String command : commands){
PermissionRequest request = PermissionContext.COMMAND_PREQUESTS.get(command);
if (request != null){
request.setLevel(level);
}else {
logger.warn("未找到command:{}指定的请求资源定义",command);
}
}
}
}

/**
* 根据HttpServletRequest获取系统中定义的请求资源信息
* @param request
* @return
*/
public static PermissionRequest getPermissionRequest(HttpServletRequest request) throws PermissionRequestException{
String sourceRequestUrl = request.getRequestURI();

String requestUrl = getApiPath(sourceRequestUrl);
String method = request.getMethod();
String command = (String) request.getAttribute(AuthorizationConstants.REQUEST_COMMAND);
// logger.info("command="+command);
if (StringUtils.isNotBlank(command) && PermissionContext.COMMAND_PREQUESTS.containsKey(command)){
return PermissionContext.COMMAND_PREQUESTS.get(command);
}
String methodRequestPath = PermissionContext.createMethodReqPath(method,requestUrl);
if (PermissionContext.URL_METHOD_PREQUESTS.containsKey(methodRequestPath)){
return PermissionContext.URL_METHOD_PREQUESTS.get(methodRequestPath);
}else if (PermissionContext.URL_METHOD_PREQUESTS.containsKey(requestUrl) ){
return PermissionContext.URL_METHOD_PREQUESTS.get(requestUrl);
}else if (PermissionContext.URL_REQS.contains(methodRequestPath)){
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setRequestPath(methodRequestPath);
permissionRequest.setRequestType(RequestType.URL);
return permissionRequest;
}else if (PermissionContext.URL_REQS.contains(requestUrl)){
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setRequestPath(requestUrl);
permissionRequest.setRequestType(RequestType.URL);
return permissionRequest;
}else if (PermissionContext.URL_REQS.contains(sourceRequestUrl)){
PermissionRequest permissionRequest = new PermissionRequest();
permissionRequest.setRequestPath(sourceRequestUrl);
permissionRequest.setRequestType(RequestType.URL);
return permissionRequest;
}

return null;
}

/**
* 合并命令配置信息
* @param commandConfig
*/
public static void mergeConfigCommand(Map<Object,Object> commandConfig) {
if(!org.springframework.util.CollectionUtils.isEmpty(commandConfig)){
for(Map.Entry<Object,Object> config : commandConfig.entrySet()){
String command = config.getKey().toString();
String methodRequest = trimMethodRequest(config.getValue().toString());
// 更新访问权限类型
if(StringUtils.isNotBlank(command) && StringUtils.isNotBlank(methodRequest)){
PermissionRequest permissionRequest = getPermissionRequest(methodRequest);
PermissionRequest commandRequest = COMMAND_PREQUESTS.get(command);

if (permissionRequest == null) {
logger.error(String.format("未找到命令%s所对应的controller 处理方法",command));
}else if (StringUtils.isNotBlank(permissionRequest.getCommand()) &&
commandRequest != null && commandRequest != permissionRequest
){
throw new PermissionInitException(String.format("command[%s]已经被请求%s定义,不可再请求%s上重复使用。",command
,commandRequest.getRequestPath()
,methodRequest
));
}else {

PermissionRequest currentPermission;
if (!Objects.equals(permissionRequest.getMethodRequestPath(),methodRequest)){
currentPermission = new PermissionRequest();
BeanUtils.copyProperties(permissionRequest,currentPermission);
currentPermission.setMethodRequestPath(methodRequest);
currentPermission.setRequestMethod(getRequestMethod(methodRequest));
}else {
currentPermission = permissionRequest;
String sourceCommand = permissionRequest.getCommand();
if (StringUtils.isNotBlank(sourceCommand)){
COMMAND_PREQUESTS.remove(sourceCommand);
}
}
currentPermission.setCommand(command);
currentPermission.setRequestType(RequestType.COMMAND);
currentPermission.setLevel(PermissionLevel.COMMAND_PERMISSION);
COMMAND_PREQUESTS.put(command,currentPermission);


}

}
}
}
}

/**
* 将资源权限定义解析为标准格式:将资源权限定义中存在的空格去掉和http请求转为大写
* @param methodRequest
* @return
*/
private static String trimMethodRequest(String methodRequest){
String[] methodRequestConfigs = methodRequest.split(",");
if (methodRequestConfigs.length < 2 ){
return "";
}
return StringUtils.trim(methodRequestConfigs[0]) + "," + StringUtils.trim(methodRequestConfigs[1]);
}

public static PermissionRequest getPermissionRequest (String methodRequest){
if (StringUtils.isBlank(methodRequest)){
return null;
}
PermissionRequest permissionRequest = URL_METHOD_PREQUESTS.get(methodRequest);
if (permissionRequest == null && StringUtils.contains(methodRequest,",")){
String url = StringUtils.split(methodRequest,",")[1];
permissionRequest = URL_METHOD_PREQUESTS.get(url);
}
return permissionRequest;
}

/**
* 因为通过servlet注册进来的url直连是对所有的请求方式都为url直连,
* 而基于servlet注册进来的url的优先级更高,所以需要重置通过注解设置的访问配置
* @param urlRequest
*/
public static void resetUrlRequest(String urlRequest){
if (!URL_REQS.contains(urlRequest)){
// 1.添加到url直连集合中
URL_REQS.add(urlRequest);
}
resetOrAddToUrlRequest(urlRequest);

for (RequestMethod method : RequestMethod.values()){
String methodRequestPath = createMethodReqPath(method,urlRequest);
resetToUrlRequest(methodRequestPath);
}
}

private static void resetToUrlRequest(String methodRequestPath) {
if (URL_METHOD_PREQUESTS.containsValue(methodRequestPath)) {
PermissionRequest request = URL_METHOD_PREQUESTS.get(methodRequestPath);
request.setRequestType(RequestType.URL);
if (StringUtils.isNotBlank(request.getCommand())) {
COMMAND_PREQUESTS.remove(request.getCommand());
}
}
}

private static void resetOrAddToUrlRequest(String methodRequestPath) {
if (URL_METHOD_PREQUESTS.containsValue(methodRequestPath)) {
PermissionRequest request = URL_METHOD_PREQUESTS.get(methodRequestPath);
request.setRequestType(RequestType.URL);
if (StringUtils.isNotBlank(request.getCommand())) {
COMMAND_PREQUESTS.remove(request.getCommand());
}
}else {
PermissionRequest request = new PermissionRequest();
request.setMethodRequestPath(methodRequestPath);
request.setRequestType(RequestType.URL);
URL_METHOD_PREQUESTS.put(methodRequestPath,request);
}
}

public static boolean containsCommand(String command){
return COMMAND_PREQUESTS.containsKey(command);
}

public static PermissionRequest getPermissionByCommand(String command){
return COMMAND_PREQUESTS.get(command);
}

public static Collection<PermissionRequest> getAllPrequests(){
return URL_METHOD_PREQUESTS.values();
}

private static RequestMethod getRequestMethod (String methodRequest){

if (StringUtils.contains(methodRequest,",")){
String methodStr = StringUtils.split(methodRequest,",")[0];
for (RequestMethod method : RequestMethod.values()){
if (method.toString().equals(methodStr.trim().toUpperCase())){
return method;
}
}
}
return RequestMethod.POST;
}

public static String getApiPath() {
return API_PATH;
}

public static void setApiPath(String apiPath) {
API_PATH = apiPath;
}

public static String getApiPath(String urlRequest){
urlRequest = StringUtils.trim(urlRequest);
if (StringUtils.startsWith(urlRequest,API_PATH)){
return StringUtils.substring(urlRequest,API_PATH.length());
}
return urlRequest;
}
}

权限访问级别

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
/**
* 〈一句话功能简述〉<br>
* Description: 权限访问级别
* @create 2019/6/25 20:34
*/
public enum PermissionLevel {
/**
* 通过command暴露的无权限控制的请求
*/
ALL,
/**
* 通过command暴露的对外提供接口服务的请求
*/
OUT_INTERFACE,
/**
* 通过command暴露的所有内部注册用户
*/
INNER_USER,
/**
* 正常会员才可以访问的请求
*/
COMMAND_NORMAL_MEMBER,
/**
* 赋权了才可以访问的请求
*/
COMMAND_PERMISSION

}

资源权限初始化异常类

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
/**
* 〈一句话功能简述〉<br>
* Description: 资源权限初始化异常类
*
* @author hillchen
* @create 2019/7/1 20:17
*/
public class PermissionInitException extends RuntimeException {

public PermissionInitException() {
}

public PermissionInitException(String message) {
super(message);
}

public PermissionInitException(String message, Throwable cause) {
super(message, cause);
}

public PermissionInitException(Throwable cause) {
super(cause);
}

public PermissionInitException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

权限资源注解

1
2
3
4
5
6
7
8
9
10
/**
* 〈一句话功能简述〉<br>
* Description: 权限资源注解
*
* @author hillchen
* @create 2019/6/25 20:54
*/
public interface CommandLevelLoader {
void loadCommandLevel();
}

webapp权限load工具

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
import com.banksteel.openerp.commons.permission.CommandLevelLoader;
import com.banksteel.openerp.commons.permission.PermissionContext;
import com.banksteel.openerp.commons.permission.PermissionLevel;

import java.util.List;
import java.util.Set;

/**
* 〈一句话功能简述〉<br>
* Description: webapp 权限load工具
*
* @author hillchen
* @create 2019/7/18 18:58
*/
public class WebCommandLevelLoader implements CommandLevelLoader {
private Set<String> inherentEscapeURIS;
/**
* 对外暴露的http接口:(需要校验用户登陆)
*/
private List<String> httpInterfaceCommands; // 对外HTTP接口命令
/**
* 登陆了后都可以访问
*/
private List<String> withoutAuthCommands; // 任何条件都放行的命令
/**
* 已开通且正常状态的会员的通用放行命令
*/
private List<String> excludeCommands; // 通用命令排除

public Set<String> getInherentEscapeURIS() {
return inherentEscapeURIS;
}

public void setInherentEscapeURIS(Set<String> inherentEscapeURIS) {
this.inherentEscapeURIS = inherentEscapeURIS;
}

public List<String> getHttpInterfaceCommands() {
return httpInterfaceCommands;
}

public void setHttpInterfaceCommands(List<String> httpInterfaceCommands) {
this.httpInterfaceCommands = httpInterfaceCommands;
}

public List<String> getWithoutAuthCommands() {
return withoutAuthCommands;
}

public void setWithoutAuthCommands(List<String> withoutAuthCommands) {
this.withoutAuthCommands = withoutAuthCommands;
}

public List<String> getExcludeCommands() {
return excludeCommands;
}

public void setExcludeCommands(List<String> excludeCommands) {
this.excludeCommands = excludeCommands;
}

@Override
public void loadCommandLevel() {
PermissionContext.resetCommand(inherentEscapeURIS, PermissionLevel.ALL);
PermissionContext.resetCommand(httpInterfaceCommands, PermissionLevel.OUT_INTERFACE);
PermissionContext.resetCommand(withoutAuthCommands,PermissionLevel.INNER_USER);
PermissionContext.resetCommand(excludeCommands,PermissionLevel.COMMAND_NORMAL_MEMBER);
}
}

mgt权限load工具

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
import com.banksteel.openerp.commons.permission.CommandLevelLoader;
import com.banksteel.openerp.commons.permission.PermissionContext;
import com.banksteel.openerp.commons.permission.PermissionLevel;
import java.util.Set;

/**
* 〈一句话功能简述〉<br>
* Description: webapp 权限load工具
*
* @author hillchen
* @create 2019/7/18 18:58
*/
public class MgtCommandLevelLoader implements CommandLevelLoader {
private Set<String> excludeURIs;

public Set<String> getExcludeURIs() {
return excludeURIs;
}
public void setExcludeURIs(Set<String> excludeURIs) {
this.excludeURIs = excludeURIs;
}

@Override
public void loadCommandLevel() {
PermissionContext.resetCommand(excludeURIs, PermissionLevel.ALL);
}
}

权限资源加载

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
import com.alibaba.dubbo.common.utils.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Set;

/**
* 〈一句话功能简述〉<br>
* Description: 权限资源注解
* @create 2019/6/25 20:54
*/
public class CommandConfigLoader {
private static Logger logger = LoggerFactory.getLogger(PermissionSpringListener.class);

private String configPath;
private Set<String> excludeUrls;

public CommandConfigLoader( String configPath, Set<String> excludeUrls) {
this.configPath = configPath;
this.excludeUrls = excludeUrls;
}

public void loadCommandConfig(){
loadAndMagerCommandConfig(configPath);
loadAndMergeUrlRequest(excludeUrls);
}
/**
* 因为通过servlet注册进来的url直连是对所有的请求方式都为url直连
* @param excludeUrls
*/
private void loadAndMergeUrlRequest(Set<String> excludeUrls){
if (CollectionUtils.isEmpty(excludeUrls)){
return;
}
for (String urlRequest : excludeUrls){
urlRequest = PermissionContext.getApiPath(urlRequest);
PermissionContext.resetUrlRequest(urlRequest);
}
}

private void loadAndMagerCommandConfig(String configPath){
if (StringUtils.isBlank(configPath)){
return;
}
try {
Properties commandConfig = loadCommandConfig(configPath);
PermissionContext.mergeConfigCommand(commandConfig);
}
catch (IOException e) {
logger.error("CustomDispatcherServlet 初始化异常", e);
}
}

private Properties loadCommandConfig(String path) throws IOException {
InputStream inputStream = null;
try {
inputStream = this.getClass().getClassLoader().getResourceAsStream(path);
if (inputStream == null){
return null;
}
Properties paths = new Properties();
paths.load(inputStream);
return paths;
}catch (IOException e) {
logger.error("load command 配置文件失败", e);
return null;
}finally {
if (inputStream != null){
inputStream.close();
}
}
}

}

controller权限扩展点

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
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Controller;

/**
* 〈一句话功能简述〉<br>
* Description: controller权限扩展点
* @create 2019/6/25 20:46
*/
public class PermissionProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class beanClazz = AopProxyUtils.ultimateTargetClass(bean);
if (beanClazz.isAnnotationPresent(Controller.class)){
PermissionContext.processBeanClass(beanClazz);
}
return bean;
}
}

权限资源请求对象

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
import lombok.Data;
import org.springframework.web.bind.annotation.RequestMethod;


/**
* 〈一句话功能简述〉<br>
* Description: 权限资源请求对象
*
* @author hillchen
* @create 2019/6/28 13:13
*/
@Data
public class PermissionRequest {
/**
* controller类上RequestMapping配置的地址
*/
private String basePath;

/**
* RequestMapping方法上的RequestMapping配置的地址
*/
private String relativePath;

/**
* 完整请求地址:basePath + relativePath
*/
private String requestPath;

/**
* GET,POST 等http请求方式
*/
private RequestMethod requestMethod;

/**
* 带了http请求方式的完整请求地址
* 例如:GET,/purchase/association/key
*/
private String methodRequestPath;

/**
* 请求暴露方式:是通过url还是command,暂时已知的url请求都为上传/下载请求
*/
private RequestType requestType;
/**
* 请求对外暴露的command,当为url暴露请求是command忽略
*/
private String command;

/**
* 请求资源权限级别
*/
private PermissionLevel level;

/**
* 定义该请求资源的controller类
*/
private Class clazz;

/**
* 定义该请求资源的方法名
*/
private String methodName;
}

资源权限初始化异常类

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
import com.banksteel.openerp.commons.exception.BuzzErrorException;

/**
* 〈一句话功能简述〉<br>
* Description: 资源权限初始化异常类
*
* @author hillchen
* @create 2019/7/1 20:17
*/
public class PermissionRequestException extends BuzzErrorException {
private int errorCode = 400;

public PermissionRequestException() {
}

public PermissionRequestException(String message) {
super(message);
}

public PermissionRequestException(String message, Throwable cause) {
super(message, cause);
}

public PermissionRequestException(Throwable cause) {
super(cause);
}

public PermissionRequestException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}

@Override
public int getErrorCode() {
return errorCode;
}

@Override
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
}

controller权限扩展点

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
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Controller;
import java.util.*;

/**
* 〈一句话功能简述〉<br>
* Description: controller权限扩展点
* @create 2019/6/25 20:46
*/
public class PermissionSpringListener implements ApplicationListener<ContextRefreshedEvent> {
private static Logger logger = LoggerFactory.getLogger(PermissionSpringListener.class);
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
// 只有在root容器初始化是才需要执行
if (context.getParent() != null){
return;
}

Map<String, Object> controllerBeans = context.getBeansWithAnnotation(Controller.class) ;
if (controllerBeans != null){
for (Object bean : controllerBeans.values()) {
processBean(bean);
}
}

Map<String, CommandConfigLoader> commandConfigLoaders = context.getBeansOfType(CommandConfigLoader.class);
if (commandConfigLoaders != null) {
for (CommandConfigLoader bean : commandConfigLoaders.values()) {
bean.loadCommandConfig();
}
}

Map<String, CommandLevelLoader> commandLevelLoader = context.getBeansOfType(CommandLevelLoader.class);
if (commandLevelLoader != null) {
for (CommandLevelLoader bean : commandLevelLoader.values()) {
bean.loadCommandLevel();
}
}
}

private void processBean(Object bean){
Class beanClazz = AopProxyUtils.ultimateTargetClass(bean);
PermissionContext.processBeanClass(beanClazz);
}
}

请求访问类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 〈一句话功能简述〉<br>
* Description: 请求访问类型
*
* @author hillchen
* @create 2019/6/25 20:34
*/
public enum RequestType {
/**
* 通过原生URL暴露的请求
*/
URL,
/**
* 通过命令暴露的请求
*/
COMMAND
}