diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaAnnotationStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaAnnotationStrategy.java index ad5cee77..9c8b88ba 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaAnnotationStrategy.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaAnnotationStrategy.java @@ -19,6 +19,7 @@ import cn.dev33.satoken.annotation.*; import cn.dev33.satoken.annotation.handler.*; import cn.dev33.satoken.fun.strategy.SaCheckMethodAnnotationFunction; import cn.dev33.satoken.fun.strategy.SaGetAnnotationFunction; +import cn.dev33.satoken.fun.strategy.SaIsAnnotationPresentFunction; import cn.dev33.satoken.listener.SaTokenEventCenter; import java.lang.annotation.Annotation; @@ -121,4 +122,12 @@ public final class SaAnnotationStrategy { return element.getAnnotation(annotationClass); }; + /** + * 判断一个 Method 或其所属 Class 是否包含指定注解 + */ + public SaIsAnnotationPresentFunction isAnnotationPresent = (method, annotationClass) -> { + return instance.getAnnotation.apply(method, annotationClass) != null || + instance.getAnnotation.apply(method.getDeclaringClass(), annotationClass) != null; + }; + } diff --git a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/satoken/custom_annotation/CheckAccount.java b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/satoken/custom_annotation/CheckAccount.java new file mode 100644 index 00000000..2c01a5ae --- /dev/null +++ b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/satoken/custom_annotation/CheckAccount.java @@ -0,0 +1,33 @@ +package com.pj.satoken.custom_annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 账号校验:在标注一个方法上时,要求前端必须提交相应的账号密码参数才能访问方法。 + * + * @author click33 + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE}) +public @interface CheckAccount { + + /** + * 需要校验的账号 + * + * @return / + */ + String name(); + + /** + * 需要校验的密码 + * + * @return / + */ + String pwd(); + + +} diff --git a/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/satoken/custom_annotation/handler/CheckAccountHandler.java b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/satoken/custom_annotation/handler/CheckAccountHandler.java new file mode 100644 index 00000000..f7f9c6e6 --- /dev/null +++ b/sa-token-demo/sa-token-demo-solon/src/main/java/com/pj/satoken/custom_annotation/handler/CheckAccountHandler.java @@ -0,0 +1,42 @@ +package com.pj.satoken.custom_annotation.handler; + +import cn.dev33.satoken.annotation.handler.SaAnnotationAbstractHandler; +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.exception.SaTokenException; +import com.pj.satoken.custom_annotation.CheckAccount; +import org.noear.solon.annotation.Component; + +import java.lang.reflect.Method; + +/** + * 注解 CheckAccount 的处理器 + * + * @author click33 + * + */ +@Component +public class CheckAccountHandler implements SaAnnotationAbstractHandler { + + // 指定这个处理器要处理哪个注解 + @Override + public Class getHandlerAnnotationClass() { + return CheckAccount.class; + } + + // 每次请求校验注解时,会执行的方法 + @Override + public void checkMethod(CheckAccount at, Method method) { + // 获取前端请求提交的参数 + String name = SaHolder.getRequest().getParamNotNull("name"); + String pwd = SaHolder.getRequest().getParamNotNull("pwd"); + + // 与注解中指定的值相比较 + if(name.equals(at.name()) && pwd.equals(at.pwd()) ) { + // 校验通过,什么也不做 + } else { + // 校验不通过,则抛出异常 + throw new SaTokenException("账号或密码错误,未通过校验"); + } + } + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java index 99403d0d..559a38b9 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java @@ -15,10 +15,10 @@ */ package cn.dev33.satoken.oauth2.logic; -import cn.dev33.satoken.basic.SaBasicUtil; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.context.model.SaResponse; +import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; import cn.dev33.satoken.oauth2.SaOAuth2Manager; import cn.dev33.satoken.oauth2.config.SaOAuth2Config; import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode; @@ -27,11 +27,7 @@ import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Api; import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.GrantType; import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Param; import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.ResponseType; -import cn.dev33.satoken.oauth2.model.AccessTokenModel; -import cn.dev33.satoken.oauth2.model.ClientTokenModel; -import cn.dev33.satoken.oauth2.model.CodeModel; -import cn.dev33.satoken.oauth2.model.RequestAuthModel; -import cn.dev33.satoken.oauth2.model.SaClientModel; +import cn.dev33.satoken.oauth2.model.*; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaResult; @@ -179,7 +175,7 @@ public class SaOAuth2Handle { */ public static Object token(SaRequest req, SaResponse res, SaOAuth2Config cfg) { // 获取参数 - String authorizationValue = SaBasicUtil.getAuthorizationValue(); + String authorizationValue = SaHttpBasicUtil.getAuthorizationValue(); String clientId; String clientSecret; // gitlab回调token接口时,按照的是标准的oauth2协议的basic请求头,basic中会包含client_id和client_secret的信息 diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java index 4cd41f73..bbff6026 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/XPluginImp.java @@ -16,11 +16,12 @@ package cn.dev33.satoken.solon; import cn.dev33.satoken.SaManager; -import cn.dev33.satoken.httpauth.basic.SaHttpBasicTemplate; -import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; +import cn.dev33.satoken.annotation.handler.SaAnnotationAbstractHandler; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.context.second.SaTokenSecondContextCreator; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.httpauth.basic.SaHttpBasicTemplate; +import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; import cn.dev33.satoken.httpauth.digest.SaHttpDigestTemplate; import cn.dev33.satoken.httpauth.digest.SaHttpDigestUtil; import cn.dev33.satoken.json.SaJsonTemplate; @@ -36,6 +37,7 @@ import cn.dev33.satoken.solon.sso.SaSsoAutoConfigure; import cn.dev33.satoken.stp.StpInterface; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; import cn.dev33.satoken.temp.SaTempInterface; import org.noear.solon.Solon; import org.noear.solon.core.AppContext; @@ -95,6 +97,11 @@ public class XPluginImp implements Plugin { SaTokenEventCenter.registerListener(sl); }); + // 注入自定义注解处理器 Bean (可以有多个) + context.subBeansOfType(SaAnnotationAbstractHandler.class, sl -> { + SaAnnotationStrategy.instance.registerAnnotationHandler(sl); + }); + // 注入权限认证 Bean context.getBeanAsync(StpInterface.class, bean -> { SaManager.setStpInterface(bean); diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java index 9efb5189..b833788d 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenFilter.java @@ -23,6 +23,7 @@ import cn.dev33.satoken.filter.SaFilterAuthStrategy; import cn.dev33.satoken.filter.SaFilterErrorStrategy; import cn.dev33.satoken.filter.SaFilter; import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; import cn.dev33.satoken.strategy.SaStrategy; import org.noear.solon.Solon; import org.noear.solon.core.handle.*; @@ -202,16 +203,13 @@ public class SaTokenFilter implements SaFilter, Filter { //之所以改名,为 private boolean authAnno(Action action) { //2.验证注解处理 if (isAnnotation && action != null) { - // 获取此请求对应的 Method 处理函数 - Method method = action.method().getMethod(); - - // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权 - if (SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) { + // 注解校验 + try{ + Method method = action.method().getMethod(); + SaAnnotationStrategy.instance.checkMethodAnnotation.accept(method); + } catch (StopMatchException ignored) { return false; } - - // 注解校验 - SaStrategy.instance.checkMethodAnnotation.accept(method); } return true; diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java index 5c74b370..62460cd7 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/integration/SaTokenInterceptor.java @@ -15,7 +15,6 @@ */ package cn.dev33.satoken.solon.integration; -import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.exception.BackResultException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.exception.StopMatchException; @@ -23,7 +22,7 @@ import cn.dev33.satoken.filter.SaFilter; import cn.dev33.satoken.filter.SaFilterAuthStrategy; import cn.dev33.satoken.filter.SaFilterErrorStrategy; import cn.dev33.satoken.router.SaRouter; -import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; import org.noear.solon.core.handle.*; import org.noear.solon.core.route.RouterInterceptor; import org.noear.solon.core.route.RouterInterceptorChain; @@ -237,16 +236,13 @@ public class SaTokenInterceptor implements SaFilter, RouterInterceptor { private boolean authAnno(Action action) { //2.验证注解处理 if (isAnnotation && action != null) { - // 获取此请求对应的 Method 处理函数 - Method method = action.method().getMethod(); - - // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权 - if (SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) { + // 注解校验 + try{ + Method method = action.method().getMethod(); + SaAnnotationStrategy.instance.checkMethodAnnotation.accept(method); + } catch (StopMatchException ignored) { return false; } - - // 注解校验 - SaStrategy.instance.checkMethodAnnotation.accept(method); } return true; diff --git a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java index e6c0fc13..f42e892a 100644 --- a/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java +++ b/sa-token-starter/sa-token-spring-boot3-starter/src/main/java/cn/dev33/satoken/interceptor/SaInterceptor.java @@ -15,18 +15,16 @@ */ package cn.dev33.satoken.interceptor; -import java.lang.reflect.Method; - -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerInterceptor; - -import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.exception.BackResultException; import cn.dev33.satoken.exception.StopMatchException; import cn.dev33.satoken.fun.SaParamFunction; -import cn.dev33.satoken.strategy.SaStrategy; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.lang.reflect.Method; /** * Sa-Token 综合拦截器,提供注解鉴权和路由拦截鉴权能力 @@ -96,18 +94,8 @@ public class SaInterceptor implements HandlerInterceptor { // 这里必须确保 handler 是 HandlerMethod 类型时,才能进行注解鉴权 if(isAnnotation && handler instanceof HandlerMethod) { - - // 获取此请求对应的 Method 处理函数 Method method = ((HandlerMethod) handler).getMethod(); - - // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权 - if(SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) { - // 注意这里直接就退出整个鉴权了,最底部的 auth.run() 路由拦截鉴权也被跳出了 - return true; - } - - // 注解校验 - SaStrategy.instance.checkMethodAnnotation.accept(method); + SaAnnotationStrategy.instance.checkMethodAnnotation.accept(method); } // Auth 校验