From d22f8f0ea9b64ec81fc37ddb0ef6b3984acd5d4f Mon Sep 17 00:00:00 2001 From: fanpeng Date: Mon, 5 Sep 2022 00:08:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=B4=A6=E6=88=B7=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=E6=80=A7=E6=B3=A8=E8=A7=A3=E5=8F=8A=E9=89=B4=E6=9D=83?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/annotation/SaCheckEnable.java | 24 ++++++++++++++ .../satoken/annotation/SaCheckLogin.java | 5 +++ .../java/cn/dev33/satoken/stp/StpLogic.java | 18 ++++++++--- .../cn/dev33/satoken/strategy/SaStrategy.java | 14 ++++----- sa-token-doc/doc/use/at-check.md | 31 ++++++++++++++----- .../cn/dev33/satoken/solon/XPluginImp.java | 7 ++--- 6 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/annotation/SaCheckEnable.java 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); //集成初始化