SpringAOP实现自定义接口权限控制

 更新时间:2023年11月06日 10:34:34   作者:秃了也弱了。  
本文主要介绍了SpringAOP实现自定义接口权限控制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Java技术迷

一、接口鉴权方案分析

1、接口鉴权方案

目前大部分接口鉴权方案,一般都是采用 【用户-角色-权限】模型。

将接口与权限进行编码死绑定,同时角色与权限进行动态绑定,用户与角色也进行动态绑定。

2、角色分配权限树

创建用户之后,用户可以分配多个角色。

创建角色之后,通过查询代码内置的权限树,进行角色与权限绑定,存入数据库中

二、编码实战

1、定义权限树与常用方法

使用枚举进行权限的定义,通过四级权限树,将权限分为模块、单元、功能级、接口。接口权限精细分配:

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
/**
 * 接口权限枚举定义类
 */
public enum AuthPermission {
    /**
     * 四级权限树
     * 1 模块
     * - 2 功能
     * - - 3 接口集(一般是Controller)
     * - - - 4 具体接口(@RequestMapping)
     *
     */
 
    // 用户管理
    User("user", "用户", Type.Module),
 
    SysUser(User, "系统用户", Type.Unit),
    SysUserManager(SysUser, "系统用户管理", Type.Bunch),
    SysUserManagerSelect(SysUserManager, "系统用户查询", Type.Function),
    SysUserManagerAdd(SysUserManager, "系统用户新增", Type.Function),
    SysUserManagerUpdate(SysUserManager, "系统用户修改", Type.Function),
    SysUserManagerDelete(SysUserManager, "系统用户删除", Type.Function),
 
    NormalUser(User, "普通用户", Type.Unit),
    NormalUserManager(NormalUser, "普通用户管理", Type.Bunch),
    NormalUserManagerSelect(NormalUserManager, "普通用户查询", Type.Function),
    NormalUserManagerAdd(NormalUserManager, "普通用户新增", Type.Function),
    NormalUserManagerUpdate(NormalUserManager, "普通用户修改", Type.Function),
    NormalUserManagerDelete(NormalUserManager, "普通用户删除", Type.Function),
 
    // 订单管理
    Order("order", "订单", Type.Module),
 
    OrderConfirm(Order, "下单管理", Type.Unit),
    OrderConfirmKill(OrderConfirm, "秒杀下单管理", Type.Bunch),
    OrderConfirmKillAdd(OrderConfirmKill, "秒杀订单新增", Type.Function),
    OrderConfirmKillDelete(OrderConfirmKill, "秒杀订单删除", Type.Function),
 
    OrderConfirmNormal(OrderConfirm, "普通下单管理", Type.Bunch),
    OrderConfirmNormalAdd(OrderConfirmNormal, "普通订单新增", Type.Function),
    OrderConfirmNormalDelete(OrderConfirmNormal, "普通订单删除", Type.Function),
 
    // ...其他
    ;
 
 
    /**
     * 功能权限类型
     */
    public enum Type {
        Module, // 功能模块
        Unit, // 功能单元
        Bunch, // 功能接口集
        Function, // 功能接口
    }
 
    // 模块
    private final String module;
    // 名称
    private final String title;
    // 父
    private final AuthPermission parent;
    // 类型
    private final Type type;
 
    AuthPermission(AuthPermission parent, String title, Type type) {
        this(parent.module, parent, title, type);
    }
 
    AuthPermission(String title, String module, Type type) {
        this(module, null, title, type);
    }
 
    AuthPermission(String module, AuthPermission parent, String title, Type type) {
        this.module = module;
        this.title = title;
        this.parent = parent;
        this.type = type;
    }
 
    public String getModule() {
        return module;
    }
 
    public String getTitle() {
        return title;
    }
 
    public AuthPermission getParent() {
        return parent;
    }
 
    public Type getType() {
        return type;
    }
}
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
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * 接口权限管理类
 */
public class AuthPermissionManagement {
 
    private static List<AuthArchetype> permissionTree = new ArrayList<>();
 
    private static Map<AuthPermission, AuthArchetype> permissionMap = new HashMap<>();
 
    static {
        // 递归设置树
        // 设置子树
        recursePermissions(permissionTree, permissionMap, null);
    }
 
    public static void main(String[] args) {
        // 获取权限树(到时候给前端展示树)
        System.out.println(Json.toJson(getPermissionTree()));
 
        // 校验权限
        System.out.println(checkPermission(AuthPermission.NormalUserManagerDelete, AuthPermission.NormalUser));
        System.out.println(checkPermission(AuthPermission.NormalUserManagerDelete, AuthPermission.OrderConfirm));
        System.out.println(checkPermission(AuthPermission.NormalUserManagerDelete, AuthPermission.NormalUserManagerDelete));
 
    }
 
    /**
     * 校验权限 递归
     * @param userPermission 用户角色权限
     * @param interfacePermission 接口权限
     * @return
     */
    public static boolean checkPermission(AuthPermission userPermission, AuthPermission interfacePermission) {
        if (userPermission == interfacePermission) {
            return true;
        }
        // 有子接口权限也可
        AuthArchetype authArchetype = permissionMap.get(interfacePermission);
        if (authArchetype == null) {
            return false;
        }
        return checkChildrenPermission(userPermission, authArchetype);
    }
 
    private static boolean checkChildrenPermission(AuthPermission userPermission, AuthArchetype authArchetype) {
        if (authArchetype.getName().equals(userPermission.name())) {
            return true;
        }
        if (!CollectionUtils.isEmpty(authArchetype.getSubPermissions())) {
            for (AuthArchetype subPermission : authArchetype.getSubPermissions()) {
                if (subPermission.getName().equals(userPermission.name())) {
                    return true;
                }
                // 递归
                if (checkChildrenPermission(userPermission, subPermission)) {
                    return true;
                }
            }
        }
        return false;
    }
 
    // 获取权限树
    public static List<AuthArchetype> getPermissionTree() {
        return permissionTree;
    }
 
    private static void recursePermissions(List<AuthArchetype> permissionTree, Map<AuthPermission, AuthArchetype> permissionMap, AuthPermission current) {
        for (AuthPermission permission : AuthPermission.values()) {
            if (permission.getParent() == current) {
                AuthArchetype permissionArchetype = new AuthArchetype(permission);
                if (current == null) {
                    permissionTree.add(permissionArchetype);
                } else {
                    permissionMap.get(current).addSubPermission(permissionArchetype);
                }
                permissionMap.put(permission, permissionArchetype);
                recursePermissions(permissionTree, permissionMap, permission);
 
            }
 
        }
    }
 
 
    public static class AuthArchetype {
        // name
        private String name;
        // 模块
        private String module;
        // 名称
        private String title;
        // 父
        private AuthPermission parent;
        // 类型
        private AuthPermission.Type type;
        // 子
        private List<AuthArchetype> subPermissions;
 
        public AuthArchetype(AuthPermission permission) {
            this.name = permission.name();
            this.module = permission.getModule();
            this.title = permission.getTitle();
            this.parent = permission.getParent();
            this.type = permission.getType();
        }
 
        public void addSubPermission(AuthArchetype subPermission) {
            if (this.subPermissions == null) {
                this.subPermissions = new ArrayList<>();
            }
            this.subPermissions.add(subPermission);
        }
 
        public String getName() {
            return name;
        }
 
        public void setName(String name) {
            this.name = name;
        }
 
        public String getModule() {
            return module;
        }
 
        public void setModule(String module) {
            this.module = module;
        }
 
        public String getTitle() {
            return title;
        }
 
        public void setTitle(String title) {
            this.title = title;
        }
 
        public AuthPermission getParent() {
            return parent;
        }
 
        public void setParent(AuthPermission parent) {
            this.parent = parent;
        }
 
        public AuthPermission.Type getType() {
            return type;
        }
 
        public void setType(AuthPermission.Type type) {
            this.type = type;
        }
 
        public List<AuthArchetype> getSubPermissions() {
            return subPermissions;
        }
 
        public void setSubPermissions(List<AuthArchetype> subPermissions) {
            this.subPermissions = subPermissions;
        }
    }
}

2、自定义AOP注解

1
2
3
4
5
6
7
8
9
10
11
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Auth {
 
    AuthPermission[] value() default {};
}

3、AOP切面类(也可以用拦截器实现)

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
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
 
import java.lang.reflect.Method;
 
@Aspect
@Component
public class AuthAdvice {
 
    /**
     * 我们希望的是如果方法上有注解,则对方法进行限制,若方法上无注解,单是类上有注解,那么类上的权限注解对该类下所有的接口生效。
     */
    @Around("@annotation(com.qstcloud.athena.opencourse.auth.Auth) || @within(com.qstcloud.athena.opencourse.auth.Auth)")
    public Object preAuth(ProceedingJoinPoint point) throws Throwable {
        if (handleAuth(point)) {
            return point.proceed();
        }
        throw new RuntimeException("权限不足,请求被拒绝");
    }
 
    /**
     * 逻辑判断,返回true or false
     * true :权限校验通过
     * false :权限校验不通过
     */
    private boolean handleAuth(ProceedingJoinPoint point) {
        MethodSignature ms = point.getSignature() instanceof MethodSignature ? (MethodSignature) point.getSignature() : null;
        Method method = ms.getMethod();
        // 读取权限注解,优先方法上,没有则读取类
        Auth Annotation = getAnnotation(method, Auth.class);
 
 
        // 判断权限
        AuthPermission[] authPermissions = Annotation.value();
        if (ArrayUtils.isEmpty(authPermissions)) {
            // 没有权限树,登录就可以访问
            return checkLogin();
        }
        // 校验当前登录用户,是否包含其中权限之一
        return checkHasPermission(authPermissions);
 
    }
 
    /**
     * 校验当前登录用户,是否包含其中权限之一
     */
    private boolean checkHasPermission(AuthPermission[] authPermissions) {
//        User user = UserUtil.getCurrentUser();
//        Role role = user.getRole(); // 获取角色
 
        // TODO 判断角色中的权限,是否包含接口的权限
        return ArrayUtils.contains(authPermissions, AuthPermission.NormalUserManagerUpdate);
    }
 
    /**
     * 判断是否登录
     */
    private boolean checkLogin() {
        // TODO 从redis或者session中判断是否登录
        return true;
    }
 
    /**
     * 读取权限注解,优先方法上,没有则读取类
     */
    private Auth getAnnotation(Method method, Class<Auth> authClass) {
        Auth annotation = method.getAnnotation(authClass);
        if (annotation != null) {
            return annotation;
        }
 
        annotation = method.getDeclaringClass().getAnnotation(authClass);
        return annotation;
    }
}

4、测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController
@RequestMapping("/test")
@Auth
public class TestController {
 
 
    @GetMapping("/test1")
    public String test1() {
        return "success";
    }
 
    @GetMapping("/test2")
    @Auth(AuthPermission.NormalUserManagerDelete)
    public String test2() {
        return "success";
    }
 
    @GetMapping("/test3")
    @Auth(AuthPermission.NormalUserManagerUpdate)
    public String test3() {
        return "success";
    }
}

 到此这篇关于SpringAOP实现自定义接口权限控制的文章就介绍到这了,更多相关SpringAOP 接口权限控制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:https://blog.csdn.net/A_art_xiang/article/details/134210757

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

最新评论