diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java index f762a28f..4074d5b3 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/SaManager.java @@ -32,7 +32,7 @@ public class SaManager { /** * 配置文件 Bean */ - private static SaTokenConfig config; + public static SaTokenConfig config; public static void setConfig(SaTokenConfig config) { SaManager.config = config; if(config.getIsPrint()) { diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index 94dc03c7..cc4495fc 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -304,5 +304,4 @@ public class SaFoxUtil { } } - } diff --git a/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml index 3976cdce..65ebe15e 100644 --- a/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml @@ -2,38 +2,38 @@ server: port: 8081 -spring: - # Sa-Token配置 - sa-token: - # Token名称 (同时也是cookie名称) - token-name: satoken - # Token有效期,单位s 默认30天, -1代表永不过期 - timeout: 2592000 - # Token风格 - token-style: uuid - # 配置Sa-Token单独使用的Redis连接 - alone-redis: - # Redis数据库索引(默认为0) - database: 2 - # Redis服务器地址 - host: 127.0.0.1 - # Redis服务器连接端口 - port: 6379 - # Redis服务器连接密码(默认为空) - password: - # 连接超时时间(毫秒) - timeout: 10ms - lettuce: - pool: - # 连接池最大连接数 - max-active: 200 - # 连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms - # 连接池中的最大空闲连接 - max-idle: 10 - # 连接池中的最小空闲连接 - min-idle: 0 +# Sa-Token配置 +sa-token: + # Token名称 (同时也是cookie名称) + token-name: satoken + # Token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # Token风格 + token-style: uuid + # 配置Sa-Token单独使用的Redis连接 + alone-redis: + # Redis数据库索引(默认为0) + database: 2 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间(毫秒) + timeout: 10ms + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 +spring: # 配置业务使用的Redis连接 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-jwt/pom.xml b/sa-token-demo/sa-token-demo-jwt/pom.xml index e83aeb71..a4bb5357 100644 --- a/sa-token-demo/sa-token-demo-jwt/pom.xml +++ b/sa-token-demo/sa-token-demo-jwt/pom.xml @@ -82,7 +82,7 @@ javax.xml.bind jaxb-api - 2.3.1 + diff --git a/sa-token-demo/sa-token-demo-jwt/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-jwt/src/main/resources/application.yml index d0790c3e..14a193d4 100644 --- a/sa-token-demo/sa-token-demo-jwt/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-jwt/src/main/resources/application.yml @@ -2,21 +2,21 @@ server: port: 8081 +# sa-token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: true + # token风格 + token-style: uuid spring: - # sa-token配置 - sa-token: - # token名称 (同时也是cookie名称) - token-name: satoken - # token有效期,单位s 默认30天, -1代表永不过期 - timeout: 2592000 - # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 - activity-timeout: -1 - # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - allow-concurrent-login: true - # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) - is-share: true - # token风格 - token-style: uuid # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java index ab94b4c6..9647d18c 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -68,5 +68,5 @@ public class SaTokenConfigure implements WebMvcConfigurer { }) ; } - + } diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/MySaTokenAction.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/MySaTokenAction.java new file mode 100644 index 00000000..069abc81 --- /dev/null +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/MySaTokenAction.java @@ -0,0 +1,52 @@ +package com.pj.satoken.at; + +import java.lang.reflect.AnnotatedElement; + +import org.springframework.core.annotation.AnnotatedElementUtils; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.action.SaTokenActionDefaultImpl; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaCheckSafe; + +/** + * 继承Sa-Token行为Bean默认实现, 重写部分逻辑 + */ +//@Component +public class MySaTokenAction extends SaTokenActionDefaultImpl { + + /** + * 重写Sa-Token的注解处理器,加强注解合并功能 + * @param target see note + */ + @Override + protected void validateAnnotation(AnnotatedElement target) { + + // 校验 @SaCheckLogin 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckLogin.class)) { + SaCheckLogin at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckLogin.class); + SaManager.getStpLogic(at.type()).checkByAnnotation(at); + } + + // 校验 @SaCheckRole 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckRole.class)) { + SaCheckRole at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckRole.class); + SaManager.getStpLogic(at.type()).checkByAnnotation(at); + } + + // 校验 @SaCheckPermission 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckPermission.class)) { + SaCheckPermission at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckPermission.class); + SaManager.getStpLogic(at.type()).checkByAnnotation(at); + } + + // 校验 @SaCheckSafe 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckSafe.class)) { + SaCheckSafe at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckSafe.class); + SaManager.getStpLogic(null).checkByAnnotation(at); + } + } + +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckLogin.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckLogin.java new file mode 100644 index 00000000..74014898 --- /dev/null +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckLogin.java @@ -0,0 +1,21 @@ +package com.pj.satoken.at; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import cn.dev33.satoken.annotation.SaCheckLogin; + +/** + * 登录认证(User版):只有登录之后才能进入该方法 + *

可标注在函数、类上(效果等同于标注在此类的所有方法上) + * @author kong + * + */ +@SaCheckLogin(type = StpUserUtil.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE}) +public @interface SaUserCheckLogin { + +} diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckPermission.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckPermission.java new file mode 100644 index 00000000..38312116 --- /dev/null +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckPermission.java @@ -0,0 +1,38 @@ +package com.pj.satoken.at; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.core.annotation.AliasFor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; + +/** + * 权限认证(User版):必须具有指定权限才能进入该方法 + *

可标注在函数、类上(效果等同于标注在此类的所有方法上) + * @author kong + * + */ +@SaCheckPermission(type = StpUserUtil.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE}) +public @interface SaUserCheckPermission { + + /** + * 需要校验的权限码 + * @return 需要校验的权限码 + */ + @AliasFor(annotation = SaCheckPermission.class) + String [] value() default {}; + + /** + * 验证模式:AND | OR,默认AND + * @return 验证模式 + */ + @AliasFor(annotation = SaCheckPermission.class) + SaMode mode() default SaMode.AND; + +} diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckRole.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckRole.java new file mode 100644 index 00000000..c9b44f32 --- /dev/null +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/SaUserCheckRole.java @@ -0,0 +1,38 @@ +package com.pj.satoken.at; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.core.annotation.AliasFor; + +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaMode; + +/** + * 角色认证(User版):必须具有指定角色标识才能进入该方法 + *

可标注在函数、类上(效果等同于标注在此类的所有方法上) + * @author kong + * + */ +@SaCheckRole(type = StpUserUtil.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE}) +public @interface SaUserCheckRole { + + /** + * 需要校验的角色标识 + * @return 需要校验的角色标识 + */ + @AliasFor(annotation = SaCheckRole.class) + String [] value() default {}; + + /** + * 验证模式:AND | OR,默认AND + * @return 验证模式 + */ + @AliasFor(annotation = SaCheckRole.class) + SaMode mode() default SaMode.AND; + +} diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java new file mode 100644 index 00000000..d98b11b5 --- /dev/null +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at/StpUserUtil.java @@ -0,0 +1,697 @@ +package com.pj.satoken.at; + +import java.util.List; + +import org.springframework.stereotype.Component; + +import cn.dev33.satoken.fun.SaFunction; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.SaTokenInfo; +import cn.dev33.satoken.stp.StpLogic; + +/** + * Sa-Token 权限验证工具类 (User版) + * @author kong + */ +@Component +public class StpUserUtil { + + /** + * 账号类型标识 + */ + public static final String TYPE = "user"; + + /** + * 底层的 StpLogic 对象 + */ + public static StpLogic stpLogic = new StpLogic(TYPE); + + /** + * 获取当前 StpLogic 的账号类型 + * @return See Note + */ + public static String getLoginType(){ + return stpLogic.getLoginType(); + } + + + // =================== 获取token 相关 =================== + + /** + * 返回token名称 + * @return 此StpLogic的token名称 + */ + public static String getTokenName() { + return stpLogic.getTokenName(); + } + + /** + * 在当前会话写入当前TokenValue + * @param tokenValue token值 + * @param cookieTimeout Cookie存活时间(秒) + */ + public static void setTokenValue(String tokenValue, int cookieTimeout){ + stpLogic.setTokenValue(tokenValue, cookieTimeout); + } + + /** + * 获取当前TokenValue + * @return 当前tokenValue + */ + public static String getTokenValue() { + return stpLogic.getTokenValue(); + } + + /** + * 获取当前会话的Token信息 + * @return token信息 + */ + public static SaTokenInfo getTokenInfo() { + return stpLogic.getTokenInfo(); + } + + + // =================== 登录相关操作 =================== + + /** + * 会话登录 + * @param id 账号id,建议的类型:(long | int | String) + */ + public static void login(Object id) { + stpLogic.login(id); + } + + /** + * 会话登录,并指定登录设备 + * @param id 账号id,建议的类型:(long | int | String) + * @param device 设备标识 + */ + public static void login(Object id, String device) { + stpLogic.login(id, device); + } + + /** + * 会话登录,并指定是否 [记住我] + * @param id 账号id,建议的类型:(long | int | String) + * @param isLastingCookie 是否为持久Cookie + */ + public static void login(Object id, boolean isLastingCookie) { + stpLogic.login(id, isLastingCookie); + } + + /** + * 会话登录,并指定所有登录参数Model + * @param id 登录id,建议的类型:(long | int | String) + * @param loginModel 此次登录的参数Model + */ + public static void login(Object id, SaLoginModel loginModel) { + stpLogic.login(id, loginModel); + } + + /** + * 会话注销 + */ + public static void logout() { + stpLogic.logout(); + } + + /** + * 会话注销,根据指定Token + * @param tokenValue 指定token + */ + public static void logoutByTokenValue(String tokenValue) { + stpLogic.logoutByTokenValue(tokenValue); + } + + /** + * 会话注销,根据账号id (踢人下线) + *

当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2 + * @param loginId 账号id + */ + public static void logoutByLoginId(Object loginId) { + stpLogic.logoutByLoginId(loginId); + } + + /** + * 会话注销,根据账号id & 设备标识 (踢人下线) + *

当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2 + * @param loginId 账号id + * @param device 设备标识 + */ + public static void logoutByLoginId(Object loginId, String device) { + stpLogic.logoutByLoginId(loginId, device); + } + + // 查询相关 + + /** + * 当前会话是否已经登录 + * @return 是否已登录 + */ + public static boolean isLogin() { + return stpLogic.isLogin(); + } + + /** + * 检验当前会话是否已经登录,如未登录,则抛出异常 + */ + public static void checkLogin() { + stpLogic.checkLogin(); + } + + /** + * 获取当前会话账号id, 如果未登录,则抛出异常 + * @return 账号id + */ + public static Object getLoginId() { + return stpLogic.getLoginId(); + } + + /** + * 获取当前会话账号id, 如果未登录,则返回默认值 + * @param 返回类型 + * @param defaultValue 默认值 + * @return 登录id + */ + public static T getLoginId(T defaultValue) { + return stpLogic.getLoginId(defaultValue); + } + + /** + * 获取当前会话账号id, 如果未登录,则返回null + * @return 账号id + */ + public static Object getLoginIdDefaultNull() { + return stpLogic.getLoginIdDefaultNull(); + } + + /** + * 获取当前会话账号id, 并转换为String类型 + * @return 账号id + */ + public static String getLoginIdAsString() { + return stpLogic.getLoginIdAsString(); + } + + /** + * 获取当前会话账号id, 并转换为int类型 + * @return 账号id + */ + public static int getLoginIdAsInt() { + return stpLogic.getLoginIdAsInt(); + } + + /** + * 获取当前会话账号id, 并转换为long类型 + * @return 账号id + */ + public static long getLoginIdAsLong() { + return stpLogic.getLoginIdAsLong(); + } + + /** + * 获取指定Token对应的账号id,如果未登录,则返回 null + * @param tokenValue token + * @return 账号id + */ + public static Object getLoginIdByToken(String tokenValue) { + return stpLogic.getLoginIdByToken(tokenValue); + } + + + // =================== session相关 =================== + + /** + * 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回 + * @param loginId 账号id + * @param isCreate 是否新建 + * @return Session对象 + */ + public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) { + return stpLogic.getSessionByLoginId(loginId, isCreate); + } + + /** + * 获取指定key的Session, 如果Session尚未创建,则返回null + * @param sessionId SessionId + * @return Session对象 + */ + public static SaSession getSessionBySessionId(String sessionId) { + return stpLogic.getSessionBySessionId(sessionId); + } + + /** + * 获取指定账号id的Session,如果Session尚未创建,则新建并返回 + * @param loginId 账号id + * @return Session对象 + */ + public static SaSession getSessionByLoginId(Object loginId) { + return stpLogic.getSessionByLoginId(loginId); + } + + /** + * 获取当前会话的Session, 如果Session尚未创建,isCreate=是否新建并返回 + * @param isCreate 是否新建 + * @return Session对象 + */ + public static SaSession getSession(boolean isCreate) { + return stpLogic.getSession(isCreate); + } + + /** + * 获取当前会话的Session,如果Session尚未创建,则新建并返回 + * @return Session对象 + */ + public static SaSession getSession() { + return stpLogic.getSession(); + } + + + // =================== token专属session =================== + + /** + * 获取指定Token-Session,如果Session尚未创建,则新建并返回 + * @param tokenValue Token值 + * @return Session对象 + */ + public static SaSession getTokenSessionByToken(String tokenValue) { + return stpLogic.getTokenSessionByToken(tokenValue); + } + + /** + * 获取当前Token-Session,如果Session尚未创建,则新建并返回 + * @return Session对象 + */ + public static SaSession getTokenSession() { + return stpLogic.getTokenSession(); + } + + + // =================== [临时过期] 验证相关 =================== + + /** + * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常 + */ + public static void checkActivityTimeout() { + stpLogic.checkActivityTimeout(); + } + + /** + * 续签当前token:(将 [最后操作时间] 更新为当前时间戳) + *

请注意: 即时token已经 [临时过期] 也可续签成功, + * 如果此场景下需要提示续签失败,可在此之前调用 checkActivityTimeout() 强制检查是否过期即可

+ */ + public static void updateLastActivityToNow() { + stpLogic.updateLastActivityToNow(); + } + + + // =================== 过期时间相关 =================== + + /** + * 获取当前登录者的token剩余有效时间 (单位: 秒) + * @return token剩余有效时间 + */ + public static long getTokenTimeout() { + return stpLogic.getTokenTimeout(); + } + + /** + * 获取当前登录者的Session剩余有效时间 (单位: 秒) + * @return token剩余有效时间 + */ + public static long getSessionTimeout() { + return stpLogic.getSessionTimeout(); + } + + /** + * 获取当前token的专属Session剩余有效时间 (单位: 秒) + * @return token剩余有效时间 + */ + public static long getTokenSessionTimeout() { + return stpLogic.getTokenSessionTimeout(); + } + + /** + * 获取当前token[临时过期]剩余有效时间 (单位: 秒) + * @return token[临时过期]剩余有效时间 + */ + public static long getTokenActivityTimeout() { + return stpLogic.getTokenActivityTimeout(); + } + + + + // =================== 角色验证操作 =================== + + /** + * 指定账号id是否含有角色标识, 返回true或false + * @param loginId 账号id + * @param role 角色标识 + * @return 是否含有指定角色标识 + */ + public static boolean hasRole(Object loginId, String role) { + return stpLogic.hasRole(loginId, role); + } + + /** + * 当前账号是否含有指定角色标识, 返回true或false + * @param role 角色标识 + * @return 是否含有指定角色标识 + */ + public static boolean hasRole(String role) { + return stpLogic.hasRole(role); + } + + /** + * 当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException + * @param role 角色标识 + */ + public static void checkRole(String role) { + stpLogic.checkRole(role); + } + + /** + * 当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] + * @param roleArray 角色标识数组 + */ + public static void checkRoleAnd(String... roleArray){ + stpLogic.checkRoleAnd(roleArray); + } + + /** + * 当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] + * @param roleArray 角色标识数组 + */ + public static void checkRoleOr(String... roleArray){ + stpLogic.checkRoleOr(roleArray); + } + + + // =================== 权限验证操作 =================== + + /** + * 指定账号id是否含有指定权限, 返回true或false + * @param loginId 账号id + * @param permission 权限码 + * @return 是否含有指定权限 + */ + public static boolean hasPermission(Object loginId, String permission) { + return stpLogic.hasPermission(loginId, permission); + } + + /** + * 当前账号是否含有指定权限, 返回true或false + * @param permission 权限码 + * @return 是否含有指定权限 + */ + public static boolean hasPermission(String permission) { + return stpLogic.hasPermission(permission); + } + + /** + * 当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException + * @param permission 权限码 + */ + public static void checkPermission(String permission) { + stpLogic.checkPermission(permission); + } + + /** + * 当前账号是否含有指定权限 [指定多个,必须全部验证通过] + * @param permissionArray 权限码数组 + */ + public static void checkPermissionAnd(String... permissionArray) { + stpLogic.checkPermissionAnd(permissionArray); + } + + /** + * 当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] + * @param permissionArray 权限码数组 + */ + public static void checkPermissionOr(String... permissionArray) { + stpLogic.checkPermissionOr(permissionArray); + } + + + // =================== id 反查token 相关操作 =================== + + /** + * 获取指定账号id的tokenValue + *

在配置为允许并发登录时,此方法只会返回队列的最后一个token, + * 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId + * @param loginId 账号id + * @return token值 + */ + public static String getTokenValueByLoginId(Object loginId) { + return stpLogic.getTokenValueByLoginId(loginId); + } + + /** + * 获取指定账号id指定设备端的tokenValue + *

在配置为允许并发登录时,此方法只会返回队列的最后一个token, + * 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId + * @param loginId 账号id + * @param device 设备标识 + * @return token值 + */ + public static String getTokenValueByLoginId(Object loginId, String device) { + return stpLogic.getTokenValueByLoginId(loginId, device); + } + + /** + * 获取指定账号id的tokenValue集合 + * @param loginId 账号id + * @return 此loginId的所有相关token + */ + public static List getTokenValueListByLoginId(Object loginId) { + return stpLogic.getTokenValueListByLoginId(loginId); + } + + /** + * 获取指定账号id指定设备端的tokenValue 集合 + * @param loginId 账号id + * @param device 设备标识 + * @return 此loginId的所有相关token + */ + public static List getTokenValueListByLoginId(Object loginId, String device) { + return stpLogic.getTokenValueListByLoginId(loginId, device); + } + + /** + * 返回当前会话的登录设备 + * @return 当前令牌的登录设备 + */ + public static String getLoginDevice() { + return stpLogic.getLoginDevice(); + } + + + // =================== 会话管理 =================== + + /** + * 根据条件查询Token + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return token集合 + */ + public static List searchTokenValue(String keyword, int start, int size) { + return stpLogic.searchTokenValue(keyword, start, size); + } + + /** + * 根据条件查询SessionId + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public static List searchSessionId(String keyword, int start, int size) { + return stpLogic.searchSessionId(keyword, start, size); + } + + /** + * 根据条件查询Token专属Session的Id + * @param keyword 关键字 + * @param start 开始处索引 (-1代表查询所有) + * @param size 获取数量 + * @return sessionId集合 + */ + public static List searchTokenSessionId(String keyword, int start, int size) { + return stpLogic.searchTokenSessionId(keyword, start, size); + } + + + // ------------------- 账号封禁 ------------------- + + /** + * 封禁指定账号 + *

此方法不会直接将此账号id踢下线,而是在对方再次登录时抛出`DisableLoginException`异常 + * @param loginId 指定账号id + * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁) + */ + public static void disable(Object loginId, long disableTime) { + stpLogic.disable(loginId, disableTime); + } + + /** + * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) + * @param loginId 账号id + * @return see note + */ + public static boolean isDisable(Object loginId) { + return stpLogic.isDisable(loginId); + } + + /** + * 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁) + * @param loginId 账号id + * @return see note + */ + public static long getDisableTime(Object loginId) { + return stpLogic.getDisableTime(loginId); + } + + /** + * 解封指定账号 + * @param loginId 账号id + */ + public static void untieDisable(Object loginId) { + stpLogic.untieDisable(loginId); + } + + + // =================== 身份切换 =================== + + /** + * 临时切换身份为指定账号id + * @param loginId 指定loginId + */ + public static void switchTo(Object loginId) { + stpLogic.switchTo(loginId); + } + + /** + * 结束临时切换身份 + */ + public static void endSwitch() { + stpLogic.endSwitch(); + } + + /** + * 当前是否正处于[身份临时切换]中 + * @return 是否正处于[身份临时切换]中 + */ + public static boolean isSwitch() { + return stpLogic.isSwitch(); + } + + /** + * 在一个代码段里方法内,临时切换身份为指定账号id + * @param loginId 指定账号id + * @param function 要执行的方法 + */ + public static void switchTo(Object loginId, SaFunction function) { + stpLogic.switchTo(loginId, function); + } + + + // ------------------- 二级认证 ------------------- + + /** + * 在当前会话 开启二级认证 + * @param timeout 维持时间 (单位: 秒) + */ + public static void openSafe(long safeTime) { + stpLogic.openSafe(safeTime); + } + + /** + * 当前会话 是否处于二级认证时间内 + * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时 + */ + public static boolean isSafe() { + return stpLogic.isSafe(); + } + + /** + * 检查当前会话是否已通过二级认证,如未通过则抛出异常 + */ + public static void checkSafe() { + stpLogic.checkSafe(); + } + + /** + * 获取当前会话的二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证) + * @return + */ + public static long getSafeTime() { + return stpLogic.getSafeTime(); + } + + /** + * 在当前会话 结束二级认证 + */ + public static void closeSafe() { + stpLogic.closeSafe(); + } + + + // =================== 历史API,兼容旧版本 =================== + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.getLoginType() ,使用方式保持不变

+ * 获取当前StpLogin的loginKey + * @return 当前StpLogin的loginKey + */ + @Deprecated + public static String getLoginKey(){ + return stpLogic.getLoginType(); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变

+ * 在当前会话上登录id + * @param loginId 登录id,建议的类型:(long | int | String) + */ + @Deprecated + public static void setLoginId(Object loginId) { + stpLogic.login(loginId); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变

+ * 在当前会话上登录id, 并指定登录设备 + * @param loginId 登录id,建议的类型:(long | int | String) + * @param device 设备标识 + */ + @Deprecated + public static void setLoginId(Object loginId, String device) { + stpLogic.login(loginId, device); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变

+ * 在当前会话上登录id, 并指定登录设备 + * @param loginId 登录id,建议的类型:(long | int | String) + * @param isLastingCookie 是否为持久Cookie + */ + @Deprecated + public static void setLoginId(Object loginId, boolean isLastingCookie) { + stpLogic.login(loginId, isLastingCookie); + } + + /** + *

本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变

+ * 在当前会话上登录id, 并指定所有登录参数Model + * @param loginId 登录id,建议的类型:(long | int | String) + * @param loginModel 此次登录的参数Model + */ + @Deprecated + public static void setLoginId(Object loginId, SaLoginModel loginModel) { + stpLogic.login(loginId, loginModel); + } + +} diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java index f0c374ee..aa349254 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java +++ b/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/test/TestController.java @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.pj.satoken.at.StpUserUtil; import com.pj.util.AjaxJson; import com.pj.util.Ttime; @@ -241,7 +242,8 @@ public class TestController { @RequestMapping("test") public AjaxJson test() { System.out.println("进来了"); - return AjaxJson.getSuccess("访问成功"); + StpUserUtil.login(10001); + return AjaxJson.getSuccess(); } // 测试 浏览器访问: http://localhost:8081/test/test2 diff --git a/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml index f0f2da76..3d9b33c4 100644 --- a/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-springboot/src/main/resources/application.yml @@ -1,25 +1,25 @@ # 端口 server: port: 8081 - -spring: - # sa-token配置 - sa-token: - # token名称 (同时也是cookie名称) - token-name: satoken - # token有效期,单位s 默认30天, -1代表永不过期 - timeout: 2592000 - # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 - activity-timeout: -1 - # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: false - # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) - is-share: true - # token风格 - token-style: uuid - # 是否输出操作日志 - is-log: false +# sa-token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: false + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: true + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: false + +spring: # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-sso1/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso1/src/main/resources/application.yml index 95704ba0..540f442a 100644 --- a/sa-token-demo/sa-token-demo-sso1/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso1/src/main/resources/application.yml @@ -2,8 +2,7 @@ server: port: 8081 -spring: - sa-token: - # 写入Cookie时显式指定的作用域, 用于单点登录二级域名共享Cookie - cookie-domain: stp.com +sa-token: + # 写入Cookie时显式指定的作用域, 用于单点登录二级域名共享Cookie + cookie-domain: stp.com \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-sso2-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso2-client/src/main/resources/application.yml index 3273d6cd..a3c9d8c0 100644 --- a/sa-token-demo/sa-token-demo-sso2-client/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso2-client/src/main/resources/application.yml @@ -2,42 +2,41 @@ server: port: 9001 -spring: - # sa-token配置 - sa-token: - # Token名称 - token-name: satoken - # Token有效期 - timeout: 2592000 - # Token风格 - token-style: uuid - # SSO-相关配置 - sso: - # SSO-Server端 单点登录地址 - auth-url: http://sa-sso-server.com:9000/ssoAuth - - # 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis) - alone-redis: - # Redis数据库索引 - database: 1 - # Redis服务器地址 - host: 127.0.0.1 - # Redis服务器连接端口 - port: 6379 - # Redis服务器连接密码(默认为空) - password: - # 连接超时时间(毫秒) - timeout: 10ms - lettuce: - pool: - # 连接池最大连接数 - max-active: 200 - # 连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms - # 连接池中的最大空闲连接 - max-idle: 10 - # 连接池中的最小空闲连接 - min-idle: 0 +# sa-token配置 +sa-token: + # Token名称 + token-name: satoken + # Token有效期 + timeout: 2592000 + # Token风格 + token-style: uuid + # SSO-相关配置 + sso: + # SSO-Server端 单点登录地址 + auth-url: http://sa-sso-server.com:9000/ssoAuth + + # 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis) + alone-redis: + # Redis数据库索引 + database: 1 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间(毫秒) + timeout: 10ms + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 diff --git a/sa-token-demo/sa-token-demo-sso2-server/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso2-server/src/main/resources/application.yml index 847d4cba..0e298e12 100644 --- a/sa-token-demo/sa-token-demo-sso2-server/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso2-server/src/main/resources/application.yml @@ -2,16 +2,16 @@ server: port: 9000 -spring: - # Sa-Token配置 - sa-token: - # SSO-相关配置 - sso: - # Ticket有效期 (单位: 秒),默认五分钟 - ticket-timeout: 300 - # 所有允许的授权回调地址 (此处为了方便测试配置为*,线上生产环境一定要配置为详细地地址) - allow-url: http://sa-sso-client1.com:9001/ssoLogin, http://sa-sso-client2.com:9001/ssoLogin, http://sa-sso-client3.com:9001/ssoLogin +# Sa-Token配置 +sa-token: + # SSO-相关配置 + sso: + # Ticket有效期 (单位: 秒),默认五分钟 + ticket-timeout: 300 + # 所有允许的授权回调地址 (此处为了方便测试配置为*,线上生产环境一定要配置为详细地地址) + allow-url: http://sa-sso-client1.com:9001/ssoLogin, http://sa-sso-client2.com:9001/ssoLogin, http://sa-sso-client3.com:9001/ssoLogin +spring: # Redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-sso3-client/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso3-client/src/main/resources/application.yml index adf2534a..b0229669 100644 --- a/sa-token-demo/sa-token-demo-sso3-client/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso3-client/src/main/resources/application.yml @@ -2,26 +2,26 @@ server: port: 9001 -spring: - # sa-token配置 - sa-token: - # Token名称 - token-name: satoken - # Token有效期 - timeout: 2592000 - # Token风格 - token-style: uuid - # SSO-相关配置 - sso: - # SSO-Server端 单点登录地址 - auth-url: http://sa-sso-server.com:9000/ssoAuth - # SSO-Server端 ticket校验地址 - check-ticket-url: http://sa-sso-server.com:9000/checkTicket - # SSO-Server端 单点注销地址 - slo-url: http://sa-sso-server.com:9000/ssoLogout - # 接口调用秘钥(用于SSO模式三的单点注销功能) - secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +# sa-token配置 +sa-token: + # Token名称 + token-name: satoken + # Token有效期 + timeout: 2592000 + # Token风格 + token-style: uuid + # SSO-相关配置 + sso: + # SSO-Server端 单点登录地址 + auth-url: http://sa-sso-server.com:9000/ssoAuth + # SSO-Server端 ticket校验地址 + check-ticket-url: http://sa-sso-server.com:9000/checkTicket + # SSO-Server端 单点注销地址 + slo-url: http://sa-sso-server.com:9000/ssoLogout + # 接口调用秘钥(用于SSO模式三的单点注销功能) + secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +spring: # 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis) redis: # Redis数据库索引 diff --git a/sa-token-demo/sa-token-demo-sso3-server/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-sso3-server/src/main/resources/application.yml index 25264a48..98a8875a 100644 --- a/sa-token-demo/sa-token-demo-sso3-server/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-sso3-server/src/main/resources/application.yml @@ -2,18 +2,18 @@ server: port: 9000 -spring: - # Sa-Token配置 - sa-token: - # SSO-相关配置 - sso: - # Ticket有效期 (单位: 秒),默认五分钟 - ticket-timeout: 300 - # 所有允许的授权回调地址 - allow-url: http://sa-sso-client1.com:9001/ssoLogin, http://sa-sso-client2.com:9001/ssoLogin, http://sa-sso-client3.com:9001/ssoLogin - # 接口调用秘钥(用于SSO模式三的单点注销功能) - secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +# Sa-Token配置 +sa-token: + # SSO-相关配置 + sso: + # Ticket有效期 (单位: 秒),默认五分钟 + ticket-timeout: 300 + # 所有允许的授权回调地址 + allow-url: http://sa-sso-client1.com:9001/ssoLogin, http://sa-sso-client2.com:9001/ssoLogin, http://sa-sso-client3.com:9001/ssoLogin + # 接口调用秘钥(用于SSO模式三的单点注销功能) + secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +spring: # Redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml index 7ecd9cfa..24288c95 100644 --- a/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml +++ b/sa-token-demo/sa-token-demo-webflux/src/main/resources/application.yml @@ -2,23 +2,22 @@ server: port: 8081 +# sa-token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: true + # token风格 + token-style: uuid + spring: - # sa-token配置 - sa-token: - # token名称 (同时也是cookie名称) - token-name: satoken - # token有效期,单位s 默认30天, -1代表永不过期 - timeout: 2592000 - # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 - activity-timeout: -1 - # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: true - # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) - is-share: true - # token风格 - token-style: uuid - - # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/sa-token-doc/doc/plugin/alone-redis.md b/sa-token-doc/doc/plugin/alone-redis.md index 7699c7ce..d4350551 100644 --- a/sa-token-doc/doc/plugin/alone-redis.md +++ b/sa-token-doc/doc/plugin/alone-redis.md @@ -24,39 +24,37 @@ Sa-Token默认的Redis集成方式会把权限数据和业务缓存放在一起 ### 2、然后在application.yml中增加配置 ``` yml -# 端口 -spring: - # Sa-Token配置 - sa-token: - # Token名称 - token-name: satoken - # Token有效期 - timeout: 2592000 - # Token风格 - token-style: uuid - - # 配置Sa-Token单独使用的Redis连接 - alone-redis: - # Redis数据库索引(默认为0) - database: 2 - # Redis服务器地址 - host: 127.0.0.1 - # Redis服务器连接端口 - port: 6379 - # Redis服务器连接密码(默认为空) - password: - # 连接超时时间(毫秒) - timeout: 10ms - lettuce: - pool: - # 连接池最大连接数 - max-active: 200 - # 连接池最大阻塞等待时间(使用负值表示没有限制) - max-wait: -1ms - # 连接池中的最大空闲连接 - max-idle: 10 - # 连接池中的最小空闲连接 - min-idle: 0 +# Sa-Token配置 +sa-token: + # Token名称 + token-name: satoken + # Token有效期 + timeout: 2592000 + # Token风格 + token-style: uuid + + # 配置Sa-Token单独使用的Redis连接 + alone-redis: + # Redis数据库索引(默认为0) + database: 2 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间(毫秒) + timeout: 10ms + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 ``` 具体可参考:[码云:application.yml](https://gitee.com/dromara/sa-token/blob/dev/sa-token-demo/sa-token-demo-alone-redis/src/main/resources/application.yml) diff --git a/sa-token-doc/doc/plugin/temp-token.md b/sa-token-doc/doc/plugin/temp-token.md index 61fe912a..09a1b0ef 100644 --- a/sa-token-doc/doc/plugin/temp-token.md +++ b/sa-token-doc/doc/plugin/temp-token.md @@ -66,8 +66,7 @@ SaTempUtil.getTimeout(token); 并在配置文件中配置上jwt秘钥 **`(必填!)`** ``` java -spring: - sa-token: - # sa-token-temp-jwt 模块的秘钥 (随便乱摁几个字母就行了) - jwt-secret-key: JfdDSgfCmPsDfmsAaQwnXk +sa-token: + # sa-token-temp-jwt 模块的秘钥 (随便乱摁几个字母就行了) + jwt-secret-key: JfdDSgfCmPsDfmsAaQwnXk ``` diff --git a/sa-token-doc/doc/senior/sso.md b/sa-token-doc/doc/senior/sso.md index 585b0d61..495a8fa6 100644 --- a/sa-token-doc/doc/senior/sso.md +++ b/sa-token-doc/doc/senior/sso.md @@ -50,10 +50,9 @@ Sa-Token整合同域下的单点登录非常简单,相比于正常的登录, #### 2. 指定Cookie的作用域 常规情况下,在`s1.stp.com`域名访问服务器,其Cookie也只能写入到`s1.stp.com`下,为了将Cookie写入到其父级域名`stp.com`下,我们需要在配置文件中新增配置: ``` yml -spring: - sa-token: - # 写入Cookie时显式指定的作用域, 用于单点登录二级域名共享Cookie - cookie-domain: stp.com +sa-token: + # 写入Cookie时显式指定的作用域, 用于单点登录二级域名共享Cookie + cookie-domain: stp.com ``` #### 3. 新增测试Controller diff --git a/sa-token-doc/doc/sso/_sidebar.md b/sa-token-doc/doc/sso/_sidebar.md index a3fcfabc..caca6efd 100644 --- a/sa-token-doc/doc/sso/_sidebar.md +++ b/sa-token-doc/doc/sso/_sidebar.md @@ -1,11 +1,10 @@ - - **单点登录** - [单点登录简述](/sso/readme) - [SSO模式一 共享Cookie同步会话](/sso/sso-type1) - [SSO模式二 URL重定向传播会话](/sso/sso-type2) - - [SSO模式三 SSO认证中心开放接口](/sso/sso-type3) + - [SSO模式三 Http请求获取会话](/sso/sso-type3) diff --git a/sa-token-doc/doc/sso/sso-type1.md b/sa-token-doc/doc/sso/sso-type1.md index 387137ad..edd19ce9 100644 --- a/sa-token-doc/doc/sso/sso-type1.md +++ b/sa-token-doc/doc/sso/sso-type1.md @@ -39,10 +39,9 @@ OK,所有理论就绪,下面开始实战 ### 2、指定Cookie的作用域 在`s1.stp.com`访问服务器,其Cookie也只能写入到`s1.stp.com`下,为了将Cookie写入到其父级域名`stp.com`下,我们需要新增配置: ``` yml -spring: - sa-token: - # 写入Cookie时显式指定的作用域, 用于单点登录二级域名共享Cookie - cookie-domain: stp.com +sa-token: + # 写入Cookie时显式指定的作用域, 用于单点登录二级域名共享Cookie + cookie-domain: stp.com ``` ### 3、新增测试Controller diff --git a/sa-token-doc/doc/sso/sso-type2.md b/sa-token-doc/doc/sso/sso-type2.md index b7e343ca..70be878a 100644 --- a/sa-token-doc/doc/sso/sso-type2.md +++ b/sa-token-doc/doc/sso/sso-type2.md @@ -111,16 +111,16 @@ public class SsoServerController { server: port: 9000 -spring: - # Sa-Token配置 - sa-token: - # SSO-相关配置 - sso: - # Ticket有效期 (单位: 秒),默认五分钟 - ticket-timeout: 300 - # 所有允许的授权回调地址 (此处为了方便测试配置为*,线上生产环境一定要配置为详细地地址) - allow-url: "*" +# Sa-Token配置 +sa-token: + # SSO-相关配置 + sso: + # Ticket有效期 (单位: 秒),默认五分钟 + ticket-timeout: 300 + # 所有允许的授权回调地址 (此处为了方便测试配置为*,线上生产环境一定要配置为详细地地址) + allow-url: "*" +spring: # Redis配置 redis: # Redis数据库索引(默认为0) @@ -248,26 +248,25 @@ public class SsoClientController { server: port: 9001 -spring: - # sa-token配置 - sa-token: - # SSO-相关配置 - sso: - # SSO-Server端 单点登录地址 - auth-url: http://sa-sso-server.com:9000/ssoAuth - - # 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis) - alone-redis: - # Redis数据库索引 (默认为0) - database: 1 - # Redis服务器地址 - host: 127.0.0.1 - # Redis服务器连接端口 - port: 6379 - # Redis服务器连接密码(默认为空) - password: +# sa-token配置 +sa-token: + # SSO-相关配置 + sso: + # SSO-Server端 单点登录地址 + auth-url: http://sa-sso-server.com:9000/ssoAuth + + # 配置Sa-Token单独使用的Redis连接 (此处需要和SSO-Server端连接同一个Redis) + alone-redis: + # Redis数据库索引 (默认为0) + database: 1 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: ``` -注意点:`spring.sa-token.alone-redis` 的配置需要和SSO-Server端连接同一个Redis(database也要一样) +注意点:`sa-token.alone-redis` 的配置需要和SSO-Server端连接同一个Redis(database也要一样) ##### 1.4、写启动类 ``` java @@ -347,7 +346,7 @@ public class SaSsoClientApplication { ### 5、配置域名校验 ##### 5.1、Ticket劫持攻击 -在以上的SSO-Server端示例中,配置项 `spring.sa-token.sso.allow-url=*` 意为配置所有允许的Client端授权地址,不在此配置项中的URL将无法单点登录成功 +在以上的SSO-Server端示例中,配置项 `sa-token.sso.allow-url=*` 意为配置所有允许的Client端授权地址,不在此配置项中的URL将无法单点登录成功 以上示例为了方便测试被配置为*,但是,在生产环境中,此配置项绝对不能配置为 * ,否则会有被ticket劫持的风险 diff --git a/sa-token-doc/doc/sso/sso-type3.md b/sa-token-doc/doc/sso/sso-type3.md index cf993d02..58c063a4 100644 --- a/sa-token-doc/doc/sso/sso-type3.md +++ b/sa-token-doc/doc/sso/sso-type3.md @@ -55,11 +55,10 @@ public Object checkTicket(String ticket, String sloCallback) { ##### 1.3、Client端新增配置 ``` yml -spring: - sa-token: - sso: - # SSO-Server端 ticket校验地址 - check-ticket-url: http://sa-sso-server.com:9000/checkTicket +sa-token: + sso: + # SSO-Server端 ticket校验地址 + check-ticket-url: http://sa-sso-server.com:9000/checkTicket ``` ##### 1.4、修改校验ticket的逻辑 @@ -129,11 +128,10 @@ public class SsoServerLogoutController { 并在 `application.yml` 下配置API调用秘钥 ``` yml -spring: - sa-token: - sso: - # API调用秘钥(用于SSO模式三的单点注销功能) - secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +sa-token: + sso: + # API调用秘钥(用于SSO模式三的单点注销功能) + secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor ``` ##### 2.2、SSO-Client端增加注销接口 @@ -182,13 +180,12 @@ public class SsoClientLogoutController { 并在 `application.yml` 增加配置: API调用秘钥 和 单点注销接口URL ``` yml -spring: - sa-token: - sso: - # SSO-Server端 单点注销地址 - slo-url: http://sa-sso-server.com:9000/ssoLogout - # 接口调用秘钥(用于SSO模式三的单点注销功能) - secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor +sa-token: + sso: + # SSO-Server端 单点注销地址 + slo-url: http://sa-sso-server.com:9000/ssoLogout + # 接口调用秘钥(用于SSO模式三的单点注销功能) + secretkey: kQwIOrYvnXmSDkwEiFngrKidMcdrgKor ``` ##### 2.3 更改Client端首页代码 diff --git a/sa-token-doc/doc/start/download.md b/sa-token-doc/doc/start/download.md index 8b5ca060..4d7524ed 100644 --- a/sa-token-doc/doc/start/download.md +++ b/sa-token-doc/doc/start/download.md @@ -97,6 +97,7 @@ implementation 'cn.dev33:sa-token-core:1.20.0' ├── sa-token-spring-aop // [插件] Sa-Token 整合 SpringAOP 注解鉴权 ├── sa-token-temp-jwt // [插件] Sa-Token 整合 jwt 临时令牌鉴权 ├── sa-token-quick-login // [插件] Sa-Token 快速注入登录页插件 + ├── sa-token-alone-redis // [插件] Sa-Token 独立Redis插件,实现[权限缓存与业务缓存分离] ├── sa-token-oauth2 // [插件] Sa-Token 实现 OAuth2.0 模块(内测暂未发布) ├── sa-token-demo // [示例] Sa-Token 示例合集 ├── sa-token-demo-springboot // [示例] Sa-Token 整合 SpringBoot @@ -104,6 +105,12 @@ implementation 'cn.dev33:sa-token-core:1.20.0' ├── sa-token-demo-jwt // [示例] Sa-Token 集成 jwt ├── sa-token-demo-solon // [示例] Sa-Token 集成 Solon ├── sa-token-demo-quick-login // [示例] Sa-Token 集成 quick-login 模块 + ├── sa-token-demo-alone-redis // [示例] Sa-Token 集成 alone-redis 模块 + ├── sa-token-demo-sso1 // [示例] Sa-Token 集成 SSO单点登录-模式一 + ├── sa-token-demo-sso2-server // [示例] Sa-Token 集成 SSO单点登录-模式二 认证中心 + ├── sa-token-demo-sso2-client // [示例] Sa-Token 集成 SSO单点登录-模式二 应用端 + ├── sa-token-demo-sso3-server // [示例] Sa-Token 集成 SSO单点登录-模式三 认证中心 + ├── sa-token-demo-sso3-client // [示例] Sa-Token 集成 SSO单点登录-模式三 应用端 ├── sa-token-demo-oauth2-server // [示例] Sa-Token 集成 OAuth2.0 (服务端) ├── sa-token-demo-oauth2-client // [示例] Sa-Token 集成 OAuth2.0 (客户端) ├── sa-token-doc // [文档] Sa-Token 开发文档 diff --git a/sa-token-doc/doc/start/example.md b/sa-token-doc/doc/start/example.md index cdcbd342..852982f6 100644 --- a/sa-token-doc/doc/start/example.md +++ b/sa-token-doc/doc/start/example.md @@ -30,23 +30,22 @@ server: # 端口 port: 8081 -spring: - # Sa-Token配置 - sa-token: - # token名称 (同时也是cookie名称) - token-name: satoken - # token有效期,单位s 默认30天, -1代表永不过期 - timeout: 2592000 - # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 - activity-timeout: -1 - # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: false - # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) - is-share: false - # token风格 - token-style: uuid - # 是否输出操作日志 - is-log: false +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: false + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: false ``` 如果你习惯于 `application.properties` 类型的配置文件,那也很好办:
diff --git a/sa-token-doc/doc/use/config.md b/sa-token-doc/doc/use/config.md index d61cf366..60b501d5 100644 --- a/sa-token-doc/doc/use/config.md +++ b/sa-token-doc/doc/use/config.md @@ -9,27 +9,28 @@ ### 方式1、在`application.yml`配置 ``` java -spring: - # Sa-Token配置 - sa-token: - # token名称 (同时也是cookie名称) - token-name: satoken - # token有效期,单位s 默认30天, -1代表永不过期 - timeout: 2592000 - # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 - activity-timeout: -1 - # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) - is-concurrent: false - # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) - is-share: false - # token风格 - token-style: uuid - # 是否输出操作日志 - is-log: false +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: satoken + # token有效期,单位s 默认30天, -1代表永不过期 + timeout: 2592000 + # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒 + activity-timeout: -1 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: false + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token风格 + token-style: uuid + # 是否输出操作日志 + is-log: false ``` 如果你习惯于 `application.properties` 类型的配置文件,那也很好办: 百度: [springboot properties与yml 配置文件的区别](https://www.baidu.com/s?ie=UTF-8&wd=springboot%20properties%E4%B8%8Eyml%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%8C%BA%E5%88%AB) +!> 注:旧版本配置前缀为`[spring.sa-token.]`,自v1.21.0开始,均改为`[sa-token.]`,目前版本暂时向下兼容,请尽快更新 + ### 方式2、通过代码配置 ``` java @@ -40,9 +41,9 @@ spring: public class SaTokenConfigure { // 获取配置Bean (以代码的方式配置Sa-Token, 此配置会覆盖yml中的配置) - @Primary - @Bean(name="SaTokenConfigure") - public SaTokenConfig getSaTokenConfig() { + @Bean + @Primary + public SaTokenConfig getSaTokenConfigPrimary() { SaTokenConfig config = new SaTokenConfig(); config.setTokenName("satoken"); // token名称 (同时也是cookie名称) config.setTimeout(30 * 24 * 60 * 60); // token有效期,单位s 默认30天 diff --git a/sa-token-doc/doc/use/global-listener.md b/sa-token-doc/doc/use/global-listener.md index fbacdd8a..0ffc1322 100644 --- a/sa-token-doc/doc/use/global-listener.md +++ b/sa-token-doc/doc/use/global-listener.md @@ -2,7 +2,7 @@ 接口`SaTokenListener`是Sa-Token的全局侦听器,通过实现此接口,你可以在用户登陆、退出、被踢下线等关键性操作时进行一些AOP操作 -框架对此侦听器的默认实现是log日志输出,你可以通过配置`spring.sa-token.is-log=true`开启 +框架对此侦听器的默认实现是log日志输出,你可以通过配置`sa-token.is-log=true`开启 下面我们演示一下如何自定义侦听器的实现: diff --git a/sa-token-doc/doc/use/many-account.md b/sa-token-doc/doc/use/many-account.md index 672642e9..aadd9774 100644 --- a/sa-token-doc/doc/use/many-account.md +++ b/sa-token-doc/doc/use/many-account.md @@ -1,7 +1,7 @@ # 多账号验证 --- -### 需求场景 +### 0、需求场景 有的时候,我们会在一个项目中设计两套账号体系,比如一个电商系统的 `user表` 和 `admin表`
在这种场景下,如果两套账号我们都使用 `StpUtil` 类的API进行登录鉴权,那么势必会发生逻辑冲突 @@ -9,7 +9,7 @@ 要解决这个问题,我们必须有一个合理的机制将这两套账号的授权给区分开,让它们互不干扰才行 -### 解决方案 +### 1、解决方案 以上几篇介绍的api调用,都是经过 `StpUtil` 类的各种静态方法进行授权验证, 而如果我们深入它的源码,[点此阅览](https://gitee.com/dromara/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java)
@@ -20,7 +20,7 @@ - 在构造方法时随意传入一个不同的 `loginType`,就可以再造一套账号登录体系 -### 操作示例 +### 2、操作示例 比如说,对于原生`StpUtil`类,我们只做`admin账号`权限验证,而对于`user账号`,我们则: 1. 新建一个新的权限验证类,比如: `StpUserUtil.java` @@ -44,7 +44,7 @@ public class StpUserUtil { > 成品样例参考:[码云 StpUserUtil.java](https://gitee.com/click33/sa-plus/blob/master/sp-server/src/main/java/com/pj/current/satoken/StpUserUtil.java) -### 在多账号模式下使用注解鉴权 +### 3、在多账号模式下使用注解鉴权 框架默认的注解鉴权 如`@SaCheckLogin` 只针对原生`StpUtil`进行鉴权 例如,我们在一个方法上加上`@SaCheckLogin`注解,这个注解只会放行通过`StpUtil.login(id)`进行登录的会话, @@ -64,10 +64,88 @@ public String info() { 注:`@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理,亦可根据type属性指定其校验的账号体系,此属性默认为`""`,代表使用原生`StpUtil`账号体系 +### 4、使用注解合并简化代码 +交流群里有同学反应,虽然可以根据 `@SaCheckLogin(type = "user")` 指定账号类型,但几十上百个注解都加上这个的话,还是有些繁琐,代码也不够优雅,有么有更改的解决方案? + +我们期待一种`[注解继承/合并]`的能力,即:自定义一个注解,标注上`@SaCheckLogin(type = "user")`,然后在方法上标注这个自定义注解,效果等同于标注`@SaCheckLogin(type = "user")` + +很遗憾,JDK默认的注解处理器并没有提供这种`[注解继承/合并]`的能力,不过好在我们可以利用Spring的注解处理器,达到同样的目的 + +1. 重写Sa-Token默认的注解处理器 + +``` java +/** + * 继承Sa-Token行为Bean默认实现, 重写部分逻辑 + */ +@Component +public class MySaTokenAction extends SaTokenActionDefaultImpl { + + /** + * 重写Sa-Token的注解处理器,加强注解合并功能 + */ + @Override + protected void validateAnnotation(AnnotatedElement target) { + + // 校验 @SaCheckLogin 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckLogin.class)) { + SaCheckLogin at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckLogin.class); + SaManager.getStpLogic(at.type()).checkByAnnotation(at); + } + + // 校验 @SaCheckRole 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckRole.class)) { + SaCheckRole at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckRole.class); + SaManager.getStpLogic(at.type()).checkByAnnotation(at); + } + + // 校验 @SaCheckPermission 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckPermission.class)) { + SaCheckPermission at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckPermission.class); + SaManager.getStpLogic(at.type()).checkByAnnotation(at); + } + + // 校验 @SaCheckSafe 注解 + if(AnnotatedElementUtils.isAnnotated(target, SaCheckSafe.class)) { + SaCheckSafe at = AnnotatedElementUtils.getMergedAnnotation(target, SaCheckSafe.class); + SaManager.getStpLogic(null).checkByAnnotation(at); + } + } + +} +``` + +2. 自定义一个注解 + +``` java +/** + * 登录认证(User版):只有登录之后才能进入该方法 + *

可标注在函数、类上(效果等同于标注在此类的所有方法上) + */ +@SaCheckLogin(type = "user") +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.TYPE}) +public @interface SaUserCheckLogin { + +} +``` + +3. 接下来就可以使用我们的自定义注解了 + +``` java +// 使用 @SaUserCheckLogin 的效果等同于使用:@SaCheckLogin(type = "user") +@SaUserCheckLogin +@RequestMapping("info") +public String info() { + return "查询用户信息"; +} +``` + +注:其它注解 `@SaCheckRole("xxx")`、`@SaCheckPermission("xxx")`同理,完整示例参考:[码云:自定义注解](https://gitee.com/dromara/sa-token/tree/dev/sa-token-demo/sa-token-demo-springboot/src/main/java/com/pj/satoken/at) -### 进阶 + +### 5、同端多登陆 假设我们不仅需要在后台同时集成两套账号,我们还需要在一个客户端同时登陆两套账号(业务场景举例:一个APP中可以同时登陆商家账号和用户账号) 如果我们不做任何特殊处理的话,在客户端会发生`token覆盖`,新登录的token会覆盖掉旧登录的token从而导致旧登录失效 diff --git a/sa-token-doc/doc/use/token-prefix.md b/sa-token-doc/doc/use/token-prefix.md index 3ba68229..54110cf8 100644 --- a/sa-token-doc/doc/use/token-prefix.md +++ b/sa-token-doc/doc/use/token-prefix.md @@ -14,11 +14,9 @@ 为此,我们需要在yml中添加如下配置: ``` java -spring: - # Sa-Token配置 - sa-token: - # token前缀 - tokenPrefix: Bearer +sa-token: + # token前缀 + tokenPrefix: Bearer ``` 此时 Sa-Token 便可在读取token时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx` diff --git a/sa-token-doc/doc/use/token-style.md b/sa-token-doc/doc/use/token-style.md index 0aefc418..90ab2cc2 100644 --- a/sa-token-doc/doc/use/token-style.md +++ b/sa-token-doc/doc/use/token-style.md @@ -10,7 +10,7 @@ Sa-Token默认的token生成策略是uuid风格, 其模样类似于:`623368f0-ae5e-4475-a53f-93e4225f16ae`
如果你对这种风格不太感冒,还可以将token生成设置为其他风格 -怎么设置呢?只需要在yml配置文件里设置 `spring.sa-token.token-style=风格类型` 即可,其有多种取值: +怎么设置呢?只需要在yml配置文件里设置 `sa-token.token-style=风格类型` 即可,其有多种取值: ``` java // 1. token-style=uuid —— uuid风格 (默认风格) diff --git a/sa-token-plugin/sa-token-alone-redis/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java b/sa-token-plugin/sa-token-alone-redis/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java index 75f96503..944dd419 100644 --- a/sa-token-plugin/sa-token-alone-redis/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java +++ b/sa-token-plugin/sa-token-alone-redis/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java @@ -30,7 +30,7 @@ public class SaAloneRedisInject implements EnvironmentAware{ /** * 配置信息的前缀 */ - public static final String ALONE_PREFIX = "spring.sa-token.alone-redis"; + public static final String ALONE_PREFIX = "sa-token.alone-redis"; /** * Sa-Token 持久层接口 diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaHistoryVersionInject.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaHistoryVersionInject.java new file mode 100644 index 00000000..aa3244fd --- /dev/null +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaHistoryVersionInject.java @@ -0,0 +1,59 @@ +package cn.dev33.satoken.reactor.spring; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; + +import cn.dev33.satoken.util.SaTokenConsts; + +/** + * 兼容旧版本的配置信息注入 + *

目前已处理: + *

1. yml配置前缀 [spring.sa-token.] 更改为 [sa-token.] + * @author kong + */ +public class SaHistoryVersionInject implements EnvironmentAware{ + + @Override + @SuppressWarnings("unchecked") + public void setEnvironment(Environment env) { + try { + ConfigurableEnvironment c = (ConfigurableEnvironment) env; + MutablePropertySources sources = c.getPropertySources(); + + // 将yml中所有 [spring.sa-token.] 开头的配置转移到 [sa-token.] 下 + Map newMap = new LinkedHashMap(); + for (PropertySource source : sources) { + // 根据Name开头单词判断是否为 SpringBoot .yml 或者.properties 的配置 + if(source.getName().startsWith("applicationConfig")) { + Map bootProp = (Map)source.getSource(); + for (String key : bootProp.keySet()) { + if(key != null && key.startsWith("spring.sa-token.")) { + String newKey = key.substring(7); + newMap.put(newKey, bootProp.get(key)); + } + } + } + } + + // 追加到总配置里面 + if(newMap.size() > 0) { + System.err.println("\n" + + "Sa-Token Warning: 当前配置文件方式已过时,请更改配置前缀:原 [spring.sa-token.] 更改为 [sa-token.]\n" + + "Sa-Token Warning: 当前版本(" + SaTokenConsts.VERSION_NO + ")暂时向下兼容,未来版本可能会完全移除旧形式"); + OriginTrackedMapPropertySource source = new OriginTrackedMapPropertySource("SaHistoryVersionInjectProperty", newMap); + // 追加到末尾,优先级最低 + c.getPropertySources().addLast(source); + } + } catch (Exception e) { + // not handle + } + } + +} diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenSpringAutowired.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenSpringAutowired.java index e3fa1613..062dff85 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenSpringAutowired.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/spring/SaTokenSpringAutowired.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.stereotype.Component; import org.springframework.util.PathMatcher; @@ -24,6 +25,7 @@ import cn.dev33.satoken.temp.SaTempInterface; * */ @Component +@Import(SaHistoryVersionInject.class) public class SaTokenSpringAutowired { /** @@ -32,7 +34,7 @@ public class SaTokenSpringAutowired { * @return 配置对象 */ @Bean - @ConfigurationProperties(prefix = "spring.sa-token") + @ConfigurationProperties(prefix = "sa-token") public SaTokenConfig getSaTokenConfig() { return new SaTokenConfig(); } diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaHistoryVersionInject.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaHistoryVersionInject.java new file mode 100644 index 00000000..06af474b --- /dev/null +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaHistoryVersionInject.java @@ -0,0 +1,59 @@ +package cn.dev33.satoken.spring; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.springframework.boot.env.OriginTrackedMapPropertySource; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; + +import cn.dev33.satoken.util.SaTokenConsts; + +/** + * 兼容旧版本的配置信息注入 + *

目前已处理: + *

1. yml配置前缀 [spring.sa-token.] 更改为 [sa-token.] + * @author kong + */ +public class SaHistoryVersionInject implements EnvironmentAware{ + + @Override + @SuppressWarnings("unchecked") + public void setEnvironment(Environment env) { + try { + ConfigurableEnvironment c = (ConfigurableEnvironment) env; + MutablePropertySources sources = c.getPropertySources(); + + // 将yml中所有 [spring.sa-token.] 开头的配置转移到 [sa-token.] 下 + Map newMap = new LinkedHashMap(); + for (PropertySource source : sources) { + // 根据Name开头单词判断是否为 SpringBoot .yml 或者.properties 的配置 + if(source.getName().startsWith("applicationConfig")) { + Map bootProp = (Map)source.getSource(); + for (String key : bootProp.keySet()) { + if(key != null && key.startsWith("spring.sa-token.")) { + String newKey = key.substring(7); + newMap.put(newKey, bootProp.get(key)); + } + } + } + } + + // 追加到总配置里面 + if(newMap.size() > 0) { + System.err.println("\n" + + "Sa-Token Warning: 当前配置文件方式已过时,请更改配置前缀:原 [spring.sa-token.] 更改为 [sa-token.]\n" + + "Sa-Token Warning: 当前版本(" + SaTokenConsts.VERSION_NO + ")暂时向下兼容,未来版本可能会完全移除旧形式"); + OriginTrackedMapPropertySource source = new OriginTrackedMapPropertySource("SaHistoryVersionInjectProperty", newMap); + // 追加到末尾,优先级最低 + c.getPropertySources().addLast(source); + } + } catch (Exception e) { + // not handle + } + } + +} diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenSpringAutowired.java b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenSpringAutowired.java index 117f5534..b1eb9947 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenSpringAutowired.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/main/java/cn/dev33/satoken/spring/SaTokenSpringAutowired.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.stereotype.Component; import org.springframework.util.PathMatcher; @@ -23,6 +24,7 @@ import cn.dev33.satoken.temp.SaTempInterface; * */ @Component +@Import(SaHistoryVersionInject.class) public class SaTokenSpringAutowired { /** @@ -31,11 +33,11 @@ public class SaTokenSpringAutowired { * @return 配置对象 */ @Bean - @ConfigurationProperties(prefix = "spring.sa-token") + @ConfigurationProperties(prefix = "sa-token") public SaTokenConfig getSaTokenConfig() { return new SaTokenConfig(); } - + /** * 注入配置Bean *