文章概览
- 权限管理
- 代码实现
- 用法用例
权限管理
- 什么是权限
- 用大白话举例子,校长可以审批老师的请假,但是主任还不够格无法操作,所以说校长具备审批请假的权限
- 按上面的例子,那么审批请假应该定义为一个资源,那么我用一串字符串来定义就是 audit_leave:teacher:rw.相同地,老师可以审批学生请假,那么就是audit_leave:student:rw
- 如何使用权限管理
- 权限管理的粒度可以切分到很小,可以是整个功能,可以是某个接口
- 由于题主是搞Java的,在Java社区,关于权限框架比较耳熟能详的就是Shiro,Spring Security
如何实现一个简单的接口权限管理
- 关键字 [简单/权限]
- 如何实现
- 代码实现如下:
- 定义一个用于接口方法的注解,表明该方法需要权限校验
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RequirePermission {
String[] value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,ElementType.FIELD})
public @interface PermissionParam {
String target() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface PermissionParamObj {
}
@Slf4j
@Aspect
@Component
public class PermissionProcessor {
@Before("@annotation(org.example.app.annotation.RequirePermission)")
public void checkPermission(JoinPoint joinpoint) throws Exception {
MethodSignature signature = (MethodSignature) joinpoint.getSignature()
Method method = signature.getMethod()
RequirePermission annotation = method.getAnnotation(RequirePermission.class)
if (annotation == null) {
return
}
// 所需要的权限资源
String[] value = annotation.value()
if (value == null || value.length == 0) {
return
}
Object[] args = joinpoint.getArgs()
if (args == null || args.length == 0) {
return
}
// 填充占位符
fixExpression(value, signature.getMethod(), args)
// 查找当前发现操作人的权限资源集合
Set<String> curPermissions = findCurPermissions()
// 做比较
if (checkPermission(value, curPermissions)) {
return
}
// TODO 抛个异常
}
// 填充占位符
private void fixExpression(String[] requires, Method method, Object[] args) {
// RequirePermission
Map<String, String> replaceResult = null
int arrayLength = requires.length
for (int i = 0
String expression = requires[i]
String[] strArray = StringUtils.split(expression, PermissionExpression.SPLIT)
if (strArray.length != 3) {
log.error("duck find the error permission param[length not equals 3]")
continue
}
String resourceId = strArray[1]
if (!StringUtils.startsWith(resourceId, "
continue
}
String key = StringUtils.substring(resourceId, 2, resourceId.length() - 1)
if (Objects.isNull(replaceResult)) {
replaceResult = initPermissionParamMap(method, args)
}
String value = replaceResult.get(key)
if (StringUtils.isBlank(value)) {
continue
}
// 替换
requires[i] = strArray[0] + PermissionExpression.SPLIT + value + PermissionExpression.SPLIT + strArray[2]
}
}
private Map<String, String> initPermissionParamMap(Method method, Object[] args) {
Map<String, String> map = null
for (int i = 0
MethodParameter methodParameter = new MethodParameter(method, i)
PermissionParam permissionParam = methodParameter.getParameterAnnotation(PermissionParam.class)
if (permissionParam == null) {
if (methodParameter.getParameterAnnotation(PermissionParamObj.class) == null) {
continue
}
}
// 初始化
if (map == null) {
map = new HashedMap()
}
if (permissionParam != null) {
map.put(permissionParam.target(), String.valueOf(args[i]))
} else {
// 反射遍历对象
Object arg = args[i]
findFieldAndParse(arg, map)
}
}
return map
}
private void findFieldAndParse(Object arg, Map<String, String> map) {
Class<?> aClass = arg.getClass()
while (aClass != null && !aClass.equals(Object.class)) {
Field[] fields = aClass.getDeclaredFields()
if (fields != null && fields.length > 0) {
for (Field field : fields) {
PermissionParam permissionParam = field.getAnnotation(PermissionParam.class)
if (permissionParam == null) {
continue
}
field.setAccessible(true)
try {
map.put(permissionParam.target(), String.valueOf(field.get(arg)))
} catch (Exception e) {
log.error("duck permission check error[reflection error]", e)
}
}
}
aClass = aClass.getSuperclass()
}
}
// 比对权限资源
private boolean checkPermission(String[] value, Set<String> curPermissions) {
for (String resource : value) {
if (!curPermissions.contains(resource)) {
return false
}
}
return true
}
// TODO 数据库查询
private Set<String> findCurPermissions() {
return null
}
}
结尾
- 一个简单的例子实现基于权限描述符的权限管理,实现依赖 [spring boot/spring aop/mysql]
- 感谢阅读,有什么问题或者文中有什么错误可以留言告诉我
- 今后会不断地更新掘金,当作一个技术博客来写,后续会把一些源码分析,学习思路等分享上来,欢迎关注,我也会持续优化自己的表达能力,写出更好更容易理解的文章