diff --git a/sa-token-aop/.gitignore b/sa-token-aop/.gitignore new file mode 100644 index 00000000..f56feec7 --- /dev/null +++ b/sa-token-aop/.gitignore @@ -0,0 +1,12 @@ +target/ + +node_modules/ +bin/ +.settings/ +unpackage/ +.classpath +.project + +.factorypath + +.idea/ \ No newline at end of file diff --git a/sa-token-aop/pom.xml b/sa-token-aop/pom.xml new file mode 100644 index 00000000..463be43f --- /dev/null +++ b/sa-token-aop/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + + cn.dev33 + sa-token-parent + 1.10.0 + + jar + + sa-token-aop + sa-token-aop + sa-token authentication by spring-aop + + + + + cn.dev33 + sa-token-spring-boot-starter + 1.10.0 + + + + org.springframework.boot + spring-boot-starter-aop + 2.0.0.RELEASE + + + + + + diff --git a/sa-token-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java b/sa-token-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java new file mode 100644 index 00000000..f2c35f2c --- /dev/null +++ b/sa-token-aop/src/main/java/cn/dev33/satoken/aop/SaCheckAspect.java @@ -0,0 +1,67 @@ +package cn.dev33.satoken.aop; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import cn.dev33.satoken.stp.StpLogic; +import cn.dev33.satoken.stp.StpUtil; + +/** + * sa-token 基于 Spring Aop 的注解鉴权 + * @author kong + */ +@Aspect +@Component +public class SaCheckAspect { + + /** + * 底层的 StpLogic 对象 + */ + public StpLogic stpLogic = null; + + /** + * 创建,并指定一个默认的 StpLogic + */ + public SaCheckAspect() { + this.stpLogic = StpUtil.stpLogic; + } + + /** + * 定义AOP签名 --> (切入所有使用sa-token鉴权注解的方法) + */ + public static final String POINTCUT_SIGN = "@within(cn.dev33.satoken.annotation.SaCheckLogin) || @annotation(cn.dev33.satoken.annotation.SaCheckLogin) || " + + "@within(cn.dev33.satoken.annotation.SaCheckRole) || @annotation(cn.dev33.satoken.annotation.SaCheckRole) || " + + "@within(cn.dev33.satoken.annotation.SaCheckPermission) || @annotation(cn.dev33.satoken.annotation.SaCheckPermission)"; + + /** + * 声明AOP签名 + */ + @Pointcut(POINTCUT_SIGN) + public void pointcut() { + } + + /** + * 环绕切入 + * @param joinPoint 切面对象 + * @return 底层方法执行后的返回值 + * @throws Throwable + */ + @Around("pointcut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + // 注解鉴权 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + stpLogic.checkMethodAnnotation(signature.getMethod()); + try { + // 执行原有逻辑 + Object obj = joinPoint.proceed(); + return obj; + } catch (Throwable e) { + throw e; + } + } + +} diff --git a/sa-token-aop/src/main/resources/META-INF/spring.factories b/sa-token-aop/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..9c26ddee --- /dev/null +++ b/sa-token-aop/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.aop.SaCheckAspect \ No newline at end of file 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 25a9472e..1e1f9582 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 @@ -1,5 +1,6 @@ package cn.dev33.satoken.stp; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -9,6 +10,10 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import cn.dev33.satoken.SaTokenManager; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaMode; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.exception.NotLoginException; @@ -1041,8 +1046,66 @@ public class StpLogic { return SaTokenManager.getConfig(); } + + // =================== 注解鉴权 =================== - + /** + * 对一个Method对象进行注解检查(注解鉴权内部实现) + * @param method Method对象 + */ + public void checkMethodAnnotation(Method method) { + + // ----------- 验证登录 + if(method.isAnnotationPresent(SaCheckLogin.class) || method.getDeclaringClass().isAnnotationPresent(SaCheckLogin.class)) { + this.checkLogin(); + } + + // ----------- 验证角色 + // 验证方法上的 + 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); + } + } + + // 验证通过 + } diff --git a/sa-token-demo-springboot/pom.xml b/sa-token-demo-springboot/pom.xml index 2841c58e..9ac5494c 100644 --- a/sa-token-demo-springboot/pom.xml +++ b/sa-token-demo-springboot/pom.xml @@ -51,6 +51,13 @@ org.apache.commons commons-pool2 --> + + + diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index bb3aceef..e47642d8 100644 --- a/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -3,6 +3,7 @@ package com.pj.test; import java.util.Date; import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -218,7 +219,19 @@ public class TestController { } - // 测试 浏览器访问: http://localhost:8081/test/test + @Autowired + TestService TestService; + + // 测试AOP注解鉴权: http://localhost:8081/test/testAOP + @RequestMapping("testAOP") + public AjaxJson testAOP() { + System.out.println("testAOP"); + TestService.getList(); + return AjaxJson.getSuccess(); + } + + + // 测试 浏览器访问: http://localhost:8081/test/test @RequestMapping("test") public AjaxJson test() { StpUtil.getTokenSession().logout(); diff --git a/sa-token-demo-springboot/src/main/java/com/pj/test/TestService.java b/sa-token-demo-springboot/src/main/java/com/pj/test/TestService.java new file mode 100644 index 00000000..3410ddc6 --- /dev/null +++ b/sa-token-demo-springboot/src/main/java/com/pj/test/TestService.java @@ -0,0 +1,26 @@ +package com.pj.test; + + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.stereotype.Service; + +import cn.dev33.satoken.annotation.SaCheckLogin; + +/** + * 用来测试AOP注解鉴权 + * @author kong + * + */ +@Service +//@SaCheckLogin +public class TestService { + + @SaCheckLogin + public List getList() { + System.out.println("getList"); + return new ArrayList(); + } + +} diff --git a/sa-token-doc/doc/index.html b/sa-token-doc/doc/index.html index b1275a25..786d5d16 100644 --- a/sa-token-doc/doc/index.html +++ b/sa-token-doc/doc/index.html @@ -2,11 +2,11 @@ - sa-token 官方文档 + sa-token - + diff --git a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java index 82a47625..1ab9aba2 100644 --- a/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java +++ b/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/interceptor/SaCheckInterceptor.java @@ -1,15 +1,13 @@ package cn.dev33.satoken.interceptor; +import java.lang.reflect.Method; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; -import cn.dev33.satoken.annotation.SaCheckLogin; -import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.dev33.satoken.annotation.SaCheckRole; -import cn.dev33.satoken.annotation.SaMode; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; @@ -52,56 +50,10 @@ public class SaCheckInterceptor implements HandlerInterceptor { if (handler instanceof HandlerMethod == false) { return true; } - HandlerMethod method = (HandlerMethod ) handler; + Method method = ((HandlerMethod) handler).getMethod(); - // ----------- 验证登录 - if(method.hasMethodAnnotation(SaCheckLogin.class) || method.getBeanType().isAnnotationPresent(SaCheckLogin.class)) { - stpLogic.checkLogin(); - } - - // ----------- 验证角色 - // 验证方法上的 - SaCheckRole scr = method.getMethodAnnotation(SaCheckRole.class); - if(scr != null) { - String[] roleArray = scr.value(); - if(scr.mode() == SaMode.AND) { - stpLogic.checkRoleAnd(roleArray); // 必须全部都有 - } else { - stpLogic.checkRoleOr(roleArray); // 有一个就行了 - } - } - // 验证类上的 - scr = method.getBeanType().getAnnotation(SaCheckRole.class); - if(scr != null) { - String[] roleArray = scr.value(); - if(scr.mode() == SaMode.AND) { - stpLogic.checkRoleAnd(roleArray); // 必须全部都有 - } else { - stpLogic.checkRoleOr(roleArray); // 有一个就行了 - } - } - - // ----------- 验证权限 - // 验证方法上的 - SaCheckPermission scp = method.getMethodAnnotation(SaCheckPermission.class); - if(scp != null) { - String[] permissionArray = scp.value(); - if(scp.mode() == SaMode.AND) { - stpLogic.checkPermissionAnd(permissionArray); // 必须全部都有 - } else { - stpLogic.checkPermissionOr(permissionArray); // 有一个就行了 - } - } - // 验证类上的 - scp = method.getBeanType().getAnnotation(SaCheckPermission.class); - if(scp != null) { - String[] permissionArray = scp.value(); - if(scp.mode() == SaMode.AND) { - stpLogic.checkPermissionAnd(permissionArray); // 必须全部都有 - } else { - stpLogic.checkPermissionOr(permissionArray); // 有一个就行了 - } - } + // 进行验证 + stpLogic.checkMethodAnnotation(method); // 通过验证 return true;