diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java index a7a644db..f09211a6 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckLogin.java @@ -1,5 +1,7 @@ package cn.dev33.satoken.annotation; +import cn.dev33.satoken.stp.StpUtil; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -15,4 +17,12 @@ import java.lang.annotation.Target; @Target({ ElementType.METHOD, ElementType.TYPE }) public @interface SaCheckLogin { + /** + * 多账号体系下使用哪个体系检测登录 + * 每个StpUtil都有一个stpLogic属性 + * 初始化StpLogic时, 指定的LoginKey字符串复制到这里 + * @return LoginKey字符串 + */ + String key() default "login"; + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java index 905e022e..95d7c000 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckPermission.java @@ -26,5 +26,13 @@ public @interface SaCheckPermission { * @return 验证模式 */ SaMode mode() default SaMode.AND; - + + /** + * 多账号体系下使用哪个体系检测权限 + * 每个StpUtil都有一个stpLogic属性 + * 初始化StpLogic时, 指定的LoginKey字符串复制到这里 + * @return LoginKey字符串 + */ + String key() default "login"; + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckRole.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckRole.java index 08e419e5..c11e777f 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckRole.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckRole.java @@ -26,5 +26,13 @@ public @interface SaCheckRole { * @return 验证模式 */ SaMode mode() default SaMode.AND; + + /** + * 多账号体系下使用哪个体系检测角色 + * 每个StpUtil都有一个stpLogic属性 + * 初始化StpLogic时, 指定的LoginKey字符串复制到这里 + * @return LoginKey字符串 + */ + String key() default "login"; } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotPermissionException.java b/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotPermissionException.java index 9b9e2c76..9cd0c245 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotPermissionException.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotPermissionException.java @@ -1,7 +1,5 @@ package cn.dev33.satoken.exception; -import cn.dev33.satoken.stp.StpUtil; - /** * 没有指定权限码,抛出的异常 * @@ -13,7 +11,7 @@ public class NotPermissionException extends SaTokenException { /** * 序列化版本号 */ - private static final long serialVersionUID = 6806129545290130142L; + private static final long serialVersionUID = 6806129545290130141L; /** 权限码 */ private String code; @@ -39,10 +37,6 @@ public class NotPermissionException extends SaTokenException { return loginKey; } - public NotPermissionException(String code) { - this(code, StpUtil.stpLogic.loginKey); - } - public NotPermissionException(String code, String loginKey) { super("无此权限:" + code); this.code = code; diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotRoleException.java b/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotRoleException.java index fe87c33c..fd171e44 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotRoleException.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/exception/NotRoleException.java @@ -1,7 +1,5 @@ package cn.dev33.satoken.exception; -import cn.dev33.satoken.stp.StpUtil; - /** * 没有指定角色标识,抛出的异常 * @@ -39,10 +37,6 @@ public class NotRoleException extends SaTokenException { return loginKey; } - public NotRoleException(String role) { - this(role, StpUtil.stpLogic.loginKey); - } - public NotRoleException(String role, String loginKey) { // 这里到底要不要拼接上loginKey呢?纠结 super("无此角色:" + role); diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index 790bb6a1..adeea2ca 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -1217,65 +1217,32 @@ public class StpLogic { // =================== 其它方法 =================== - + /** - * 对一个Method对象进行注解检查(注解鉴权内部实现) - * @param method Method对象 + * 检查当前登录体系是否拥有给定角色 + * @param roleArray 角色字符串数组 + * @param saMode SaMode.AND, SaMode.OR */ - public void checkMethodAnnotation(Method method) { - - // ----------- 验证登录 - if(method.isAnnotationPresent(SaCheckLogin.class) || method.getDeclaringClass().isAnnotationPresent(SaCheckLogin.class)) { - this.checkLogin(); + public void checkHasRoles(String[] roleArray, SaMode saMode) { + if(saMode == SaMode.AND) { + this.checkRoleAnd(roleArray); + } else { + this.checkRoleOr(roleArray); } - - // ----------- 验证角色 - // 验证方法上的 - SaCheckRole scr = method.getAnnotation(SaCheckRole.class); - if(scr != null) { - String[] roleArray = scr.value(); - if(scr.mode() == SaMode.AND) { - this.checkRoleAnd(roleArray); - } else { - this.checkRoleOr(roleArray); - } - } - // 验证类上的 - scr = method.getDeclaringClass().getAnnotation(SaCheckRole.class); - if(scr != null) { - String[] roleArray = scr.value(); - if(scr.mode() == SaMode.AND) { - this.checkRoleAnd(roleArray); - } else { - this.checkRoleOr(roleArray); - } - } - - // ----------- 验证权限 - // 验证方法上的 - SaCheckPermission scp = method.getAnnotation(SaCheckPermission.class); - if(scp != null) { - String[] permissionArray = scp.value(); - if(scp.mode() == SaMode.AND) { - this.checkPermissionAnd(permissionArray); - } else { - this.checkPermissionOr(permissionArray); - } - } - // 验证类上的 - scp = method.getDeclaringClass().getAnnotation(SaCheckPermission.class); - if(scp != null) { - String[] permissionArray = scp.value(); - if(scp.mode() == SaMode.AND) { - this.checkPermissionAnd(permissionArray); - } else { - this.checkPermissionOr(permissionArray); - } - } - - // 验证通过 } + /** + * 检查当前登录体系是否拥有给定权限 + * @param permissionArray 权限字符串数组 + * @param saMode SaMode.AND, SaMode.OR + */ + public void checkHasPermissions(String[] permissionArray, SaMode saMode) { + if(saMode == SaMode.AND) { + this.checkPermissionAnd(permissionArray); + } else { + this.checkPermissionOr(permissionArray); + } + } // =================== 身份切换 =================== diff --git a/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java b/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java index a57194f6..abdab736 100644 --- a/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java +++ b/sa-token-spring-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java @@ -1,5 +1,10 @@ package cn.dev33.satoken.aop; +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.exception.NotLoginException; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -12,6 +17,9 @@ import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaTokenConsts; +import java.lang.reflect.Method; +import java.util.Map; + /** * sa-token 基于 Spring Aop 的注解鉴权 * @@ -58,9 +66,66 @@ public class SaCheckAspect { */ @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + // 注解鉴权 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); - getStpLogic().checkMethodAnnotation(signature.getMethod()); + Method method = signature.getMethod(); + Class cutClass = method.getDeclaringClass(); + Map stpLogicMap = SaManager.stpLogicMap; + + // ----------- 验证登录 + SaCheckLogin checkLogin = null; + if(method.isAnnotationPresent(SaCheckLogin.class)) { // 方法注解的优先级高于类注解 + checkLogin = method.getAnnotation(SaCheckLogin.class); + } else if(cutClass.isAnnotationPresent(SaCheckLogin.class)) { + checkLogin = cutClass.getAnnotation(SaCheckLogin.class); + } + if (checkLogin != null) { + String loginKey = checkLogin.key(); + if (stpLogicMap.containsKey(loginKey)) { + StpLogic stpLogic = stpLogicMap.get(loginKey); + stpLogic.checkLogin(); + } else { + // StpUserUtil里面的StpLogic对象只有调用至少一次才会初始化,如果没有初始化SaManager.stpLogicMap里面是没有loginKey的 + // 还有一种可能是使用者写错了loginKey,这两种方式都会导致SaManager.stpLogicMap查不到loginKey + throw NotLoginException.newInstance(loginKey, NotLoginException.DEFAULT_MESSAGE); + } + } + + // ----------- 验证角色 + SaCheckRole saCheckRole = null; + if (method.isAnnotationPresent(SaCheckRole.class)) { // 方法注解的优先级高于类注解 + saCheckRole = method.getAnnotation(SaCheckRole.class); + } else if (cutClass.isAnnotationPresent(SaCheckRole.class)) { + saCheckRole = cutClass.getAnnotation(SaCheckRole.class); + } + if (saCheckRole != null) { + String loginKey = saCheckRole.key(); + if (stpLogicMap.containsKey(loginKey)) { + StpLogic stpLogic = stpLogicMap.get(loginKey); + stpLogic.checkHasRoles(saCheckRole.value(), saCheckRole.mode()); + } else { + throw NotLoginException.newInstance(loginKey, NotLoginException.DEFAULT_MESSAGE); + } + } + + // ----------- 验证权限 + SaCheckPermission saCheckPermission = null; + if (method.isAnnotationPresent(SaCheckPermission.class)) { // 方法注解的优先级高于类注解 + saCheckPermission = method.getAnnotation(SaCheckPermission.class); + } else if (cutClass.isAnnotationPresent(SaCheckPermission.class)){ + saCheckPermission = cutClass.getAnnotation(SaCheckPermission.class); + } + if (saCheckPermission != null) { + String loginKey = saCheckPermission.key(); + if (stpLogicMap.containsKey(loginKey)) { + StpLogic stpLogic = stpLogicMap.get(loginKey); + stpLogic.checkHasPermissions(saCheckPermission.value(), saCheckPermission.mode()); + } else { + throw NotLoginException.newInstance(loginKey, NotLoginException.DEFAULT_MESSAGE); + } + } + try { // 执行原有逻辑 Object obj = joinPoint.proceed(); diff --git a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java index 8729538e..318d7bf1 100644 --- a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java +++ b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaAnnotationInterceptor.java @@ -1,10 +1,16 @@ package cn.dev33.satoken.interceptor; import java.lang.reflect.Method; +import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.exception.NotLoginException; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; @@ -62,7 +68,59 @@ public class SaAnnotationInterceptor implements HandlerInterceptor { Method method = ((HandlerMethod) handler).getMethod(); // 进行验证 - getStpLogic().checkMethodAnnotation(method); + Class cutClass = method.getDeclaringClass(); + Map stpLogicMap = SaManager.stpLogicMap; + + // ----------- 验证登录 + SaCheckLogin checkLogin = null; + if(method.isAnnotationPresent(SaCheckLogin.class)) { // 方法注解的优先级高于类注解 + checkLogin = method.getAnnotation(SaCheckLogin.class); + } else if(cutClass.isAnnotationPresent(SaCheckLogin.class)) { + checkLogin = cutClass.getAnnotation(SaCheckLogin.class); + } + if (checkLogin != null) { + String loginKey = checkLogin.key(); + if (stpLogicMap.containsKey(loginKey)) { + StpLogic stpLogic = stpLogicMap.get(loginKey); + stpLogic.checkLogin(); + } else { + throw NotLoginException.newInstance(loginKey, NotLoginException.DEFAULT_MESSAGE); + } + } + + // ----------- 验证角色 + SaCheckRole saCheckRole = null; + if (method.isAnnotationPresent(SaCheckRole.class)) { // 方法注解的优先级高于类注解 + saCheckRole = method.getAnnotation(SaCheckRole.class); + } else if (cutClass.isAnnotationPresent(SaCheckRole.class)) { + saCheckRole = cutClass.getAnnotation(SaCheckRole.class); + } + if (saCheckRole != null) { + String loginKey = saCheckRole.key(); + if (stpLogicMap.containsKey(loginKey)) { + StpLogic stpLogic = stpLogicMap.get(loginKey); + stpLogic.checkHasRoles(saCheckRole.value(), saCheckRole.mode()); + } else { + throw NotLoginException.newInstance(loginKey, NotLoginException.DEFAULT_MESSAGE); + } + } + + // ----------- 验证权限 + SaCheckPermission saCheckPermission = null; + if (method.isAnnotationPresent(SaCheckPermission.class)) { // 方法注解的优先级高于类注解 + saCheckPermission = method.getAnnotation(SaCheckPermission.class); + } else if (cutClass.isAnnotationPresent(SaCheckPermission.class)){ + saCheckPermission = cutClass.getAnnotation(SaCheckPermission.class); + } + if (saCheckPermission != null) { + String loginKey = saCheckPermission.key(); + if (stpLogicMap.containsKey(loginKey)) { + StpLogic stpLogic = stpLogicMap.get(loginKey); + stpLogic.checkHasPermissions(saCheckPermission.value(), saCheckPermission.mode()); + } else { + throw NotLoginException.newInstance(loginKey, NotLoginException.DEFAULT_MESSAGE); + } + } // 通过验证 return true;