新增 SaCheckOr 注解,批量注解鉴权:只要满足其中一个注解即可通过验证

This commit is contained in:
click33
2023-05-23 05:01:16 +08:00
parent 4496242626
commit 4cf317818b
25 changed files with 241 additions and 45 deletions

View File

@@ -323,7 +323,7 @@ public class SaManager {
synchronized (SaManager.class) {
stpLogic = stpLogicMap.get(loginType);
if(stpLogic == null) {
stpLogic = SaStrategy.me.createStpLogic.apply(loginType);
stpLogic = SaStrategy.instance.createStpLogic.apply(loginType);
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright 2020-2099 sa-token.cc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.dev33.satoken.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 批量注解鉴权:只要满足其中一个注解即可通过验证
*
* <p> 可标注在方法、类上(效果等同于标注在此类的所有方法上)
*
* @author kong
* @since 1.35.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface SaCheckOr {
/**
* 设定 @SaCheckLogin参考 {@link SaCheckLogin}
*
* @return /
*/
SaCheckLogin[] login() default {};
/**
* 设定 @SaCheckPermission参考 {@link SaCheckPermission}
*
* @return /
*/
SaCheckPermission[] permission() default {};
/**
* 设定 @SaCheckRole参考 {@link SaCheckRole}
*
* @return /
*/
SaCheckRole[] role() default {};
/**
* 设定 @SaCheckSafe参考 {@link SaCheckSafe}
*
* @return /
*/
SaCheckSafe[] safe() default {};
/**
* 设定 @SaCheckBasic参考 {@link SaCheckBasic}
*
* @return /
*/
SaCheckBasic[] basic() default {};
/**
* 设定 @SaCheckDisable参考 {@link SaCheckDisable}
*
* @return /
*/
SaCheckDisable[] disable() default {};
}

View File

@@ -77,7 +77,7 @@ public class SaSessionCustomUtil {
public static SaSession getSessionById(String sessionId, boolean isCreate) {
SaSession session = SaManager.getSaTokenDao().getSession(splicingSessionKey(sessionId));
if (session == null && isCreate) {
session = SaStrategy.me.createSession.apply(splicingSessionKey(sessionId));
session = SaStrategy.instance.createSession.apply(splicingSessionKey(sessionId));
session.setType(SaTokenConsts.SESSION_TYPE__CUSTOM);
SaManager.getSaTokenDao().setSession(session, SaManager.getConfig().getTimeout());
}

View File

@@ -123,7 +123,7 @@ public class StpLogic {
* @return 生成的tokenValue
*/
public String createTokenValue(Object loginId, String device, long timeout, Map<String, Object> extraData) {
return SaStrategy.me.createToken.apply(loginId, loginType);
return SaStrategy.instance.createToken.apply(loginId, loginType);
}
/**
@@ -501,7 +501,7 @@ public class StpLogic {
}
// 4、如果代码走到此处说明未能成功复用旧 token需要根据算法新建 token
return SaStrategy.me.generateUniqueToken.execute(
return SaStrategy.instance.generateUniqueToken.execute(
"token",
getConfigOfMaxTryTimes(),
() -> {
@@ -1096,7 +1096,7 @@ public class StpLogic {
if(session == null && isCreate) {
// 创建这个 SaSession
session = SaStrategy.me.createSession.apply(sessionId);
session = SaStrategy.instance.createSession.apply(sessionId);
// 追加操作
if(appendOperation != null) {
@@ -1268,7 +1268,7 @@ public class StpLogic {
*/
if(isCreate) {
// 随机创建一个 Token
tokenValue = SaStrategy.me.generateUniqueToken.execute(
tokenValue = SaStrategy.instance.generateUniqueToken.execute(
"token",
getConfigOfMaxTryTimes(),
() -> {
@@ -2099,8 +2099,8 @@ public class StpLogic {
this.checkDisableLevel(loginId, service, at.level());
}
}
// ------------------- 账号封禁 -------------------
/**
@@ -2715,7 +2715,7 @@ public class StpLogic {
* @return /
*/
public boolean hasElement(List<String> list, String element) {
return SaStrategy.me.hasElement.apply(list, element);
return SaStrategy.instance.hasElement.apply(list, element);
}
/**

View File

@@ -28,6 +28,7 @@ import cn.dev33.satoken.util.SaTokenConsts;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.BiFunction;
@@ -58,7 +59,8 @@ public final class SaStrategy {
/**
* 获取 SaStrategy 对象的单例引用
*/
public static final SaStrategy me = new SaStrategy();
public static final SaStrategy instance = new SaStrategy();
// ----------------------- 所有策略
@@ -145,10 +147,10 @@ public final class SaStrategy {
public Consumer<Method> checkMethodAnnotation = (method) -> {
// 先校验 Method 所属 Class 上的注解
me.checkElementAnnotation.accept(method.getDeclaringClass());
instance.checkElementAnnotation.accept(method.getDeclaringClass());
// 再校验 Method 上的注解
me.checkElementAnnotation.accept(method);
instance.checkElementAnnotation.accept(method);
};
/**
@@ -156,41 +158,135 @@ public final class SaStrategy {
* <p> 参数 [element元素]
*/
public Consumer<AnnotatedElement> checkElementAnnotation = (target) -> {
// 校验 @SaCheckLogin 注解
SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.me.getAnnotation.apply(target, SaCheckLogin.class);
SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.instance.getAnnotation.apply(target, SaCheckLogin.class);
if(checkLogin != null) {
SaManager.getStpLogic(checkLogin.type(), false).checkByAnnotation(checkLogin);
}
// 校验 @SaCheckRole 注解
SaCheckRole checkRole = (SaCheckRole) SaStrategy.me.getAnnotation.apply(target, SaCheckRole.class);
SaCheckRole checkRole = (SaCheckRole) SaStrategy.instance.getAnnotation.apply(target, SaCheckRole.class);
if(checkRole != null) {
SaManager.getStpLogic(checkRole.type(), false).checkByAnnotation(checkRole);
}
// 校验 @SaCheckPermission 注解
SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.me.getAnnotation.apply(target, SaCheckPermission.class);
SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.instance.getAnnotation.apply(target, SaCheckPermission.class);
if(checkPermission != null) {
SaManager.getStpLogic(checkPermission.type(), false).checkByAnnotation(checkPermission);
}
// 校验 @SaCheckSafe 注解
SaCheckSafe checkSafe = (SaCheckSafe) SaStrategy.me.getAnnotation.apply(target, SaCheckSafe.class);
SaCheckSafe checkSafe = (SaCheckSafe) SaStrategy.instance.getAnnotation.apply(target, SaCheckSafe.class);
if(checkSafe != null) {
SaManager.getStpLogic(checkSafe.type(), false).checkByAnnotation(checkSafe);
}
// 校验 @SaCheckDisable 注解
SaCheckDisable checkDisable = (SaCheckDisable) SaStrategy.me.getAnnotation.apply(target, SaCheckDisable.class);
SaCheckDisable checkDisable = (SaCheckDisable) SaStrategy.instance.getAnnotation.apply(target, SaCheckDisable.class);
if(checkDisable != null) {
SaManager.getStpLogic(checkDisable.type(), false).checkByAnnotation(checkDisable);
}
// 校验 @SaCheckBasic 注解
SaCheckBasic checkBasic = (SaCheckBasic) SaStrategy.me.getAnnotation.apply(target, SaCheckBasic.class);
SaCheckBasic checkBasic = (SaCheckBasic) SaStrategy.instance.getAnnotation.apply(target, SaCheckBasic.class);
if(checkBasic != null) {
SaBasicUtil.check(checkBasic.realm(), checkBasic.account());
}
// 校验 @SaCheckOr 注解
SaCheckOr checkOr = (SaCheckOr) SaStrategy.instance.getAnnotation.apply(target, SaCheckOr.class);
if(checkOr != null) {
SaStrategy.instance.checkOrAnnotation.accept(checkOr);
}
};
/**
* 对一个 @SaCheckOr 进行注解校验
* <p> 参数 [SaCheckOr 注解的实例]
*/
public Consumer<SaCheckOr> checkOrAnnotation = (at) -> {
// 记录校验过程中所有的异常
List<SaTokenException> errorList = new ArrayList<>();
// 逐个开始校验 >>>
// 1、校验注解@SaCheckLogin
SaCheckLogin[] checkLoginArray = at.login();
for (SaCheckLogin item : checkLoginArray) {
try {
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
return;
} catch (SaTokenException e) {
errorList.add(e);
}
}
// 2、校验注解@SaCheckRole
SaCheckRole[] checkRoleArray = at.role();
for (SaCheckRole item : checkRoleArray) {
try {
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
return;
} catch (SaTokenException e) {
errorList.add(e);
}
}
// 3、校验注解@SaCheckPermission
SaCheckPermission[] checkPermissionArray = at.permission();
for (SaCheckPermission item : checkPermissionArray) {
try {
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
return;
} catch (SaTokenException e) {
errorList.add(e);
}
}
// 4、校验注解@SaCheckSafe
SaCheckSafe[] checkSafeArray = at.safe();
for (SaCheckSafe item : checkSafeArray) {
try {
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
return;
} catch (SaTokenException e) {
errorList.add(e);
}
}
// 5、校验注解@SaCheckDisable
SaCheckDisable[] checkDisableArray = at.disable();
for (SaCheckDisable item : checkDisableArray) {
try {
SaManager.getStpLogic(item.type(), false).checkByAnnotation(item);
return;
} catch (SaTokenException e) {
errorList.add(e);
}
}
// 6、校验注解@SaCheckBasic
SaCheckBasic[] checkBasicArray = at.basic();
for (SaCheckBasic item : checkBasicArray) {
try {
SaBasicUtil.check(item.realm(), item.account());
return;
} catch (SaTokenException e) {
errorList.add(e);
}
}
// 如果执行到这里,有两种可能:
// 可能 1. SaCheckOr 注解上不包含任何注解校验,此时 errorList 里面一个异常都没有,我们直接跳过即可
// 可能 2. 所有注解校验都通过不了,此时 errorList 里面会有多个异常,我们随便抛出一个即可
if(errorList.size() == 0) {
// return;
} else {
throw errorList.get(0);
}
};
/**
@@ -207,8 +303,8 @@ public final class SaStrategy {
* <p> 参数 [Method, 注解]
*/
public BiFunction<Method, Class<? extends Annotation>, Boolean> isAnnotationPresent = (method, annotationClass) -> {
return me.getAnnotation.apply(method, annotationClass) != null ||
me.getAnnotation.apply(method.getDeclaringClass(), annotationClass) != null;
return instance.getAnnotation.apply(method, annotationClass) != null ||
instance.getAnnotation.apply(method.getDeclaringClass(), annotationClass) != null;
};
/**
@@ -308,6 +404,18 @@ public final class SaStrategy {
return this;
}
/**
* 对一个 @SaCheckOr 进行注解校验
* <p> 参数 [SaCheckOr 注解的实例]
*
* @param checkOrAnnotation /
* @return 对象自身
*/
public SaStrategy setCheckOrAnnotation(Consumer<SaCheckOr> checkOrAnnotation) {
this.checkOrAnnotation = checkOrAnnotation;
return this;
}
/**
* 从元素上获取注解
* <p> 参数 [element元素要获取的注解类型]
@@ -355,4 +463,12 @@ public final class SaStrategy {
return this;
}
//
/**
* 请更换为 instance
*/
@Deprecated
public static final SaStrategy me = instance;
}

View File

@@ -54,7 +54,7 @@ public interface SaTempInterface {
default String createToken(String service, Object value, long timeout) {
// 生成 token
String token = SaStrategy.me.createToken.apply(null, null);
String token = SaStrategy.instance.createToken.apply(null, null);
// 持久化映射关系
String key = splicingKeyTempToken(service, token);