diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckEnable.java b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckEnable.java new file mode 100644 index 00000000..40edd32d --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckEnable.java @@ -0,0 +1,24 @@ +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; + +/** + * 校验当前用户是否可用 + * + *
可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author videomonster
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD, ElementType.TYPE })
+public @interface SaCheckEnable {
+
+ /**
+ * 多账号体系下所属的账号体系标识
+ * @return see note
+ */
+ String type() default "";
+}
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 a2cf62e6..b81ef38c 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
@@ -21,4 +21,9 @@ public @interface SaCheckLogin {
*/
String type() default "";
+ /**
+ * 是否检查当前登陆账号是否禁用 (true: 检查 false: 不检查)
+ * @return see note
+ */
+ String checkEnable() default "false";
}
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 db808d5e..268af6b5 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
@@ -6,11 +6,7 @@ import java.util.List;
import java.util.Map;
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.annotation.SaCheckSafe;
-import cn.dev33.satoken.annotation.SaMode;
+import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.config.SaCookieConfig;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.context.SaHolder;
@@ -1606,6 +1602,10 @@ public class StpLogic {
*/
public void checkByAnnotation(SaCheckLogin at) {
this.checkLogin();
+ Object loginId = getLoginId();
+ if ("true".equalsIgnoreCase(at.checkEnable().trim()) && isDisable(loginId)) {
+ throw new DisableLoginException(getLoginType(), loginId, getDisableTime(loginId));
+ }
}
/**
@@ -1656,6 +1656,14 @@ public class StpLogic {
this.checkSafe();
}
+ /**
+ * 根据注解(@SaCheckEnable)鉴权
+ *
+ * @param at 注解对象
+ */
+ public void checkByAnnotation(SaCheckEnable at) {
+ this.isDisable(getLoginId());
+ }
// ------------------- 账号封禁 -------------------
diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java
index f3f127a0..c11e562a 100644
--- a/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java
+++ b/sa-token-core/src/main/java/cn/dev33/satoken/strategy/SaStrategy.java
@@ -10,12 +10,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import cn.dev33.satoken.SaManager;
-import cn.dev33.satoken.annotation.SaCheckBasic;
-import cn.dev33.satoken.annotation.SaCheckLogin;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import cn.dev33.satoken.annotation.SaCheckRole;
-import cn.dev33.satoken.annotation.SaCheckSafe;
-import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.annotation.*;
import cn.dev33.satoken.basic.SaBasicUtil;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.util.SaFoxUtil;
@@ -168,7 +163,12 @@ public final class SaStrategy {
if(checkBasic != null) {
SaBasicUtil.check(checkBasic.realm(), checkBasic.account());
}
-
+
+ // 校验 @SaCheckEable 注解
+ SaCheckEnable checkEable = (SaCheckEnable) SaStrategy.me.getAnnotation.apply(target, SaCheckEnable.class);
+ if(checkEable != null) {
+ SaManager.getStpLogic(checkEable.type()).checkByAnnotation(checkEable);
+ }
};
/**
diff --git a/sa-token-doc/doc/use/at-check.md b/sa-token-doc/doc/use/at-check.md
index 82ae9e0b..b9999530 100644
--- a/sa-token-doc/doc/use/at-check.md
+++ b/sa-token-doc/doc/use/at-check.md
@@ -5,12 +5,13 @@
注解鉴权 —— 优雅的将鉴权与业务代码分离!
-- `@SaCheckLogin`: 登录认证 —— 只有登录之后才能进入该方法。
-- `@SaCheckRole("admin")`: 角色认证 —— 必须具有指定角色标识才能进入该方法。
-- `@SaCheckPermission("user:add")`: 权限认证 —— 必须具有指定权限才能进入该方法。
-- `@SaCheckSafe`: 二级认证校验 —— 必须二级认证之后才能进入该方法。
-- `@SaCheckBasic`: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法。
+- `@SaCheckLogin`: 登录认证 —— 只有登录之后才能进入该方法。
+- `@SaCheckRole("admin")`: 角色认证 —— 必须具有指定角色标识才能进入该方法。
+- `@SaCheckPermission("user:add")`: 权限认证 —— 必须具有指定权限才能进入该方法。
+- `@SaCheckSafe`: 二级认证校验 —— 必须二级认证之后才能进入该方法。
+- `@SaCheckBasic`: HttpBasic认证 —— 只有通过 Basic 认证后才能进入该方法。
- `@SaIgnore`:忽略认证 —— 表示被修饰的方法或类无需进行注解认证和路由拦截认证。
+- `@SaCheckEnable`:账户可用性校验 —— 校验当前操作账户是否可用, 也可以直接在`@SaCheckLogin`中设置参数`checkEnable="true""`即可完成登陆和账户可用性同事校验。
Sa-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带来不必要的性能负担,拦截器默认处于关闭状态
因此,为了使用注解鉴权,**你必须手动将 Sa-Token 的全局拦截器注册到你项目中**
@@ -20,7 +21,7 @@ Sa-Token 使用全局拦截器完成注解鉴权功能,为了不为项目带
### 1、注册拦截器
-以`SpringBoot2.0`为例,新建配置类`SaTokenConfigure.java`
+以`SpringBoot2.0`为例,新建配置类`SaTokenConfigure.java`
``` java
@Configuration
@@ -49,6 +50,13 @@ public String info() {
return "查询用户信息";
}
+// 登录认证加账户可用性认证:只有登录后, 并且账户可用才能进入该方法
+@SaCheckLogin(checkEnable = "true")
+@RequestMapping("info")
+public String info() {
+ return "查询用户信息";
+}
+
// 角色认证:必须具有指定角色才能进入该方法
@SaCheckRole("super-admin")
@RequestMapping("add")
@@ -76,6 +84,13 @@ public String add() {
public String add() {
return "用户增加";
}
+
+// 账户可用性校验: 只有当前账户可用的情况下, 才能进入方法
+@SaCheckEnable
+@RequestMapping("info")
+public String info() {
+ return "查询用户信息";
+}
```
注:以上注解都可以加在类上,代表为这个类所有方法进行鉴权
@@ -97,7 +112,7 @@ mode有两种取值:
- `SaMode.OR`, 标注一组权限,会话只要具有其一即可通过校验。
-### 4、角色权限双重 “or校验”
+### 4、角色权限双重 “or校验”
假设有以下业务场景:一个接口在具有权限 `user-add` 或角色 `admin` 时可以调通。怎么写?
``` java
@@ -115,7 +130,7 @@ orRole 字段代表权限认证未通过时的次要选择,两者只要其一
- 写法三:`orRole = {"admin, manager, staff"}`,代表必须同时具有三个角色。
-### 5、忽略认证
+### 5、忽略认证
使用 `@SaIgnore` 可表示一个接口忽略认证:
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 f7b5e800..43183a8e 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
@@ -1,16 +1,12 @@
package cn.dev33.satoken.solon;
+import cn.dev33.satoken.annotation.*;
import org.noear.solon.Solon;
import org.noear.solon.core.AopContext;
import org.noear.solon.core.Plugin;
import org.noear.solon.core.event.EventBus;
import cn.dev33.satoken.SaManager;
-import cn.dev33.satoken.annotation.SaCheckBasic;
-import cn.dev33.satoken.annotation.SaCheckLogin;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import cn.dev33.satoken.annotation.SaCheckRole;
-import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.dev33.satoken.basic.SaBasicTemplate;
import cn.dev33.satoken.basic.SaBasicUtil;
import cn.dev33.satoken.config.SaTokenConfig;
@@ -42,6 +38,7 @@ public class XPluginImp implements Plugin {
context.beanAroundAdd(SaCheckLogin.class, SaTokenAnnotationInterceptor.INSTANCE);
context.beanAroundAdd(SaCheckSafe.class, SaTokenAnnotationInterceptor.INSTANCE);
context.beanAroundAdd(SaCheckBasic.class, SaTokenAnnotationInterceptor.INSTANCE);
+ context.beanAroundAdd(SaCheckEnable.class, SaTokenAnnotationInterceptor.INSTANCE);
//集成初始化