diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginModel.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginModel.java index 144c157d..70ec71da 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginModel.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginModel.java @@ -1,12 +1,13 @@ package cn.dev33.satoken.stp; +import java.util.LinkedHashMap; +import java.util.Map; + import cn.dev33.satoken.SaManager; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.util.SaTokenConsts; -import java.util.Map; - /** * 调用 `StpUtil.login()` 时的 [配置参数 Model ] * @author kong @@ -30,9 +31,9 @@ public class SaLoginModel { public Long timeout; /** - * jwt扩展信息 + * 扩展信息(只在jwt模式下生效) */ - public Map expandInfoMap; + public Map extraData; /** @@ -84,21 +85,47 @@ public class SaLoginModel { } /** - * @return 参考 {@link #expandInfoMap} + * @return 参考 {@link #extraData} */ - public Map getExpandInfoMap() { - return expandInfoMap; + public Map getExtraData() { + return extraData; } /** - * @param expandInfoMap 参考 {@link #expandInfoMap} + * @param extraData 参考 {@link #extraData} * @return 对象自身 */ - public SaLoginModel setExpandInfoMap(Map expandInfoMap) { - this.expandInfoMap = expandInfoMap; + public SaLoginModel setExtraData(Map extraData) { + this.extraData = extraData; return this; } + /** + * 写入扩展数据(只在jwt模式下生效) + * @param key 键 + * @param value 值 + * @return + */ + public SaLoginModel setExtra(String key, Object value) { + if(this.extraData == null) { + this.extraData = new LinkedHashMap<>(); + } + this.extraData.put(key, value); + return this; + } + + /** + * 获取扩展数据(只在jwt模式下生效) + * @param key 键 + * @return 扩展数据的值 + */ + public Object getExtra(String key) { + if(this.extraData == null) { + return null; + } + return this.extraData.get(key); + } + /** * @return Cookie时长 */ 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 362ccf43..cb871585 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 @@ -16,6 +16,7 @@ import cn.dev33.satoken.context.model.SaCookie; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.context.model.SaStorage; import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.exception.ApiDisabledException; import cn.dev33.satoken.exception.DisableLoginException; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; @@ -80,26 +81,15 @@ public class StpLogic { return splicingKeyTokenName(); } - /** - * 创建一个TokenValue - * @param loginId loginId - * @param device 设备标识 - * @param timeout 过期时间 - * @return 生成的tokenValue - */ - public String createTokenValue(Object loginId, String device, long timeout) { - return SaStrategy.me.createToken.apply(loginId, loginType); - } - /** * 创建一个TokenValue * @param loginId loginId * @param device 设备标识 - * @param expandInfoMap 扩展信息 * @param timeout 过期时间 + * @param extraData 扩展信息 * @return 生成的tokenValue */ - public String createTokenValue(Object loginId, String device, Map expandInfoMap, long timeout) { + public String createTokenValue(Object loginId, String device, long timeout, Map extraData) { return SaStrategy.me.createToken.apply(loginId, loginType); } @@ -269,15 +259,6 @@ public class StpLogic { login(id, new SaLoginModel().setDevice(device)); } - /** - * 会话登录,并指定扩展信息 for Jwt - * @param id 账号id,建议的类型:(long | int | String) - * @param expandInfoMap 扩展数据 - */ - public void login(Object id, Map expandInfoMap) { - login(id, new SaLoginModel().setExpandInfoMap(expandInfoMap)); - } - /** * 会话登录,并指定是否 [记住我] * @param id 账号id,建议的类型:(long | int | String) @@ -319,7 +300,7 @@ public class StpLogic { } // 如果至此,仍未成功创建tokenValue, 则开始生成一个 if(tokenValue == null) { - tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getExpandInfoMap(), loginModel.getTimeout()); + tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData()); } // ------ 3. 获取 User-Session , 续期 @@ -678,18 +659,6 @@ public class StpLogic { return getLoginIdNotHandle(tokenValue); } - /** - * 获取指定Token对应的扩展信息,如果未登录,则返回 null - * @param tokenValue token - * @return 账号id - */ - public Object getExpandInfoByToken(String tokenValue) { - if(tokenValue == null) { - return null; - } - return getExpandInfoNotHandle(tokenValue); - } - /** * 获取指定Token对应的账号id (不做任何特殊处理) * @param tokenValue token值 @@ -700,15 +669,14 @@ public class StpLogic { } /** - * 获取指定Token对应的扩展信息 (不做任何特殊处理) - * @param tokenValue token值 - * @return 账号id + * 获取Token扩展信息(只在jwt模式下有效) + * @param key 键值 + * @return 对应的扩展数据 */ - public Object getExpandInfoNotHandle(String tokenValue) { - return getSaTokenDao().get(splicingKeyTokenValue(tokenValue)); + public Object getExtra(String key) { + throw new ApiDisabledException(); } - - + // ---- 其它操作 /** @@ -845,7 +813,7 @@ public class StpLogic { String tokenValue = getTokenValue(); if(tokenValue == null || Objects.equals(tokenValue, "")) { // 随机一个token送给Ta - tokenValue = createTokenValue(null, null, getConfig().getTimeout()); + tokenValue = createTokenValue(null, null, getConfig().getTimeout(), null); // 写入 [最后操作时间] setLastActivityToNow(tokenValue); // 在当前会话写入这个tokenValue @@ -1750,5 +1718,17 @@ public class StpLogic { public void logoutByLoginId(Object loginId, String device) { this.kickout(loginId, device); } - + + /** + * 创建一个TokenValue + * @param loginId loginId + * @param device 设备标识 + * @param timeout 过期时间 + * @return 生成的tokenValue + */ + @Deprecated + public String createTokenValue(Object loginId, String device, long timeout) { + return createTokenValue(loginId, device, timeout, null); + } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java index 8c76e64b..9df4df7b 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpUtil.java @@ -1,7 +1,6 @@ package cn.dev33.satoken.stp; import java.util.List; -import java.util.Map; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.fun.SaFunction; @@ -115,15 +114,6 @@ public class StpUtil { stpLogic.login(id, device); } - /** - * 会话登录,并指定登录设备 - * @param id 账号id,建议的类型:(long | int | String) - * @param expandInfoMap 扩展信息 - */ - public static void login(Object id, Map expandInfoMap) { - stpLogic.login(id, expandInfoMap); - } - /** * 会话登录,并指定是否 [记住我] * @param id 账号id,建议的类型:(long | int | String) @@ -298,14 +288,14 @@ public class StpUtil { } /** - * 获取指定Token对应的扩展数据,如果未登录,则返回 null - * @param tokenValue token - * @return 账号id + * 获取Token扩展信息(只在jwt模式下有效) + * @param key 键值 + * @return 对应的扩展数据 */ - public static Object getExpandInfoByToken(String tokenValue) { - return stpLogic.getExpandInfoByToken(tokenValue); + public static Object getExtra(String key) { + return stpLogic.getExtra(key); } - + // =================== User-Session 相关 =================== diff --git a/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/test/TestJwtController.java b/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/test/TestJwtController.java index db7416a5..e3a5e8f4 100644 --- a/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/test/TestJwtController.java +++ b/sa-token-demo/sa-token-demo-jwt/src/main/java/com/pj/test/TestJwtController.java @@ -73,6 +73,8 @@ public class TestJwtController { public AjaxJson test() { System.out.println(); System.out.println("--------------进入请求--------------"); + System.out.println(StpUtil.getExtra("username")); + System.out.println(StpUtil.getExtra("nick")); return AjaxJson.getSuccess(); } diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java index 7f19b001..807c516c 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/SaJwtUtil.java @@ -1,16 +1,15 @@ package cn.dev33.satoken.jwt; +import java.util.Map; + import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.util.SaFoxUtil; -import cn.hutool.core.collection.CollectionUtil; import cn.hutool.json.JSONObject; import cn.hutool.jwt.JWT; import cn.hutool.jwt.JWTException; -import java.util.Map; - /** * jwt操作工具类封装 * @author kong @@ -38,24 +37,21 @@ public class SaJwtUtil { */ public static final String EFF = "eff"; - /** - * key: 扩展数据 - */ - public static final String EXPAND = "expand"; - /** * 当有效期被设为此值时,代表永不过期 */ public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE; - + // ------ 创建 + /** * 创建 jwt (简单方式) * @param loginId 账号id + * @param extraData 扩展数据 * @param keyt 秘钥 * @return jwt-token */ - public static String createToken(Object loginId, String keyt) { + public static String createToken(Object loginId, Map extraData, String keyt) { // 秘钥不可以为空 SaTokenException.throwByNull(keyt, "请配置jwt秘钥"); @@ -65,39 +61,7 @@ public class SaJwtUtil { .setPayload(LOGIN_ID, loginId) // 混入随机字符 .setPayload("rn", SaFoxUtil.getRandomString(32)) - .setKey(keyt.getBytes()) - .sign(); - - // 返回 - return token; - } - - /** - * 创建 jwt (全参数方式) - * @param loginType 账号类型 - * @param loginId 账号id - * @param device 设备标识 - * @param timeout token有效期 (单位 秒) - * @param keyt 秘钥 - * @return jwt-token - */ - public static String createToken(String loginType, Object loginId, String device, long timeout, String keyt) { - - // 秘钥不可以为空 - SaTokenException.throwByNull(keyt, "请配置jwt秘钥"); - - // 计算有效期 - long effTime = timeout; - if(timeout != NEVER_EXPIRE) { - effTime = timeout * 1000 + System.currentTimeMillis(); - } - - // 构建 - String token = JWT.create() - .setPayload(LOGIN_TYPE, loginType) - .setPayload(LOGIN_ID, loginId) - .setPayload(DEVICE, device) - .setPayload(EFF, effTime) + .addPayloads(extraData) .setKey(keyt.getBytes()) .sign(); @@ -110,13 +74,13 @@ public class SaJwtUtil { * @param loginType 账号类型 * @param loginId 账号id * @param device 设备标识 - * @param expandInfoMap 扩展数据 * @param timeout token有效期 (单位 秒) + * @param extraData 扩展数据 * @param keyt 秘钥 * @return jwt-token */ public static String createToken(String loginType, Object loginId, String device, - Map expandInfoMap, long timeout, String keyt) { + long timeout, Map extraData, String keyt) { // 秘钥不可以为空 SaTokenException.throwByNull(keyt, "请配置jwt秘钥"); @@ -127,24 +91,22 @@ public class SaJwtUtil { effTime = timeout * 1000 + System.currentTimeMillis(); } + // 创建 JWT jwt = JWT.create() .setPayload(LOGIN_TYPE, loginType) .setPayload(LOGIN_ID, loginId) .setPayload(DEVICE, device) - .setPayload(EFF, effTime); - - // 设定扩展数据 - if (CollectionUtil.isNotEmpty(expandInfoMap)) { - jwt.setPayload(EXPAND, expandInfoMap); - } + .setPayload(EFF, effTime) + .addPayloads(extraData); // 返回 return jwt.setKey(keyt.getBytes()).sign(); } + // ------ 解析 /** - * jwt 解析(校验签名和密码) + * jwt 解析(校验签名和有效期) * @param token Jwt-Token值 * @param keyt 秘钥 * @return 解析后的jwt 对象 @@ -185,7 +147,7 @@ public class SaJwtUtil { } /** - * 获取 jwt 数据载荷 (校验签名和密码) + * 获取 jwt 数据载荷 (校验签名和有效期) * @param token token值 * @param keyt 秘钥 * @return 载荷 @@ -195,7 +157,7 @@ public class SaJwtUtil { } /** - * 获取 jwt 数据载荷 (不校验签名和密码) + * 获取 jwt 数据载荷 (只校验签名,不校验有效期) * @param token token值 * @param keyt 秘钥 * @return 载荷 @@ -204,6 +166,13 @@ public class SaJwtUtil { try { JWT jwt = JWT.of(token); JSONObject payloads = jwt.getPayloads(); + + // 校验 Token 签名 + boolean verify = jwt.setKey(keyt.getBytes()).verify(); + if(verify == false) { + throw NotLoginException.newInstance(payloads.getStr(LOGIN_TYPE), NotLoginException.INVALID_TOKEN, token); + }; + return payloads; } catch (JWTException e) { return new JSONObject(); @@ -234,33 +203,6 @@ public class SaJwtUtil { } } - /** - * getExpandMap - * - * @since 2021/11/23 5:05 下午 - * @param token token值 - * @param keyt 秘钥 - * @return 值 - */ - public static Object getExpandInfo(String token, String keyt) { - return getPayloads(token, keyt).get(EXPAND); - } - - /** - * 获取 jwt 代表的账号id (未登录时返回null) - * @param token Token值 - * @param keyt 秘钥 - * @return 值 - */ - public static Object getExpandInfoOrNull(String token, String keyt) { - try { - return getPayloads(token, keyt).get(EXPAND); - } catch (NotLoginException e) { - return null; - } - } - - /** * 获取 jwt 剩余有效期 * @param token JwtToken值 @@ -303,6 +245,32 @@ public class SaJwtUtil { // 计算timeout (转化为以秒为单位的有效时间) return (effTime - System.currentTimeMillis()) / 1000; } - - + + // ------ 废弃API + + /** + * 创建 jwt (简单方式) + * @param loginId 账号id + * @param keyt 秘钥 + * @return jwt-token + */ + @Deprecated + public static String createToken(Object loginId, String keyt) { + return createToken(loginId, null, keyt); + } + + /** + * 创建 jwt (全参数方式) + * @param loginType 账号类型 + * @param loginId 账号id + * @param device 设备标识 + * @param timeout token有效期 (单位 秒) + * @param keyt 秘钥 + * @return jwt-token + */ + @Deprecated + public static String createToken(String loginType, Object loginId, String device, long timeout, String keyt) { + return createToken(loginType, loginId, device, timeout, null, keyt); + } + } diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java index 9c7e5e78..57177dae 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMix.java @@ -51,13 +51,8 @@ public class StpLogicJwtForMix extends StpLogic { * 创建一个TokenValue */ @Override - public String createTokenValue(Object loginId, String device, long timeout) { - return SaJwtUtil.createToken(loginType, loginId, device, timeout, jwtSecretKey()); - } - - @Override - public String createTokenValue(Object loginId, String device, Map expandInfoMap, long timeout) { - return SaJwtUtil.createToken(loginType, loginId, device, expandInfoMap, timeout, jwtSecretKey()); + public String createTokenValue(Object loginId, String device, long timeout, Map extraData) { + return SaJwtUtil.createToken(loginType, loginId, device, timeout, extraData, jwtSecretKey()); } /** @@ -101,21 +96,6 @@ public class StpLogicJwtForMix extends StpLogic { } } - @Override - public Object getExpandInfoNotHandle(String tokenValue) { - // 先验证 loginType,如果不符,则视为无效token,返回null - String loginType = SaJwtUtil.getPayloadsNotCheck(tokenValue, jwtSecretKey()).getStr(SaJwtUtil.LOGIN_TYPE); - if(getLoginType().equals(loginType) == false) { - return null; - } - // 获取 expandInfo - try { - return SaJwtUtil.getExpandInfo(tokenValue, jwtSecretKey()); - } catch (NotLoginException e) { - return null; - } - } - /** * 会话注销 */ @@ -171,7 +151,15 @@ public class StpLogicJwtForMix extends StpLogic { public void replaced(Object loginId, String device) { throw new ApiDisabledException(); } - + + /** + * 获取Token携带的扩展信息 + */ + @Override + public Object getExtra(String key) { + return SaJwtUtil.getPayloads(getTokenValue(), jwtSecretKey()).get(key); + } + /** * 删除 Token-Id 映射 */ diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java index d8d89eff..04bb8c7a 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStateless.java @@ -53,13 +53,8 @@ public class StpLogicJwtForStateless extends StpLogic { * 创建一个TokenValue */ @Override - public String createTokenValue(Object loginId, String device, long timeout) { - return SaJwtUtil.createToken(loginType, loginId, device, timeout, jwtSecretKey()); - } - - @Override - public String createTokenValue(Object loginId, String device, Map expandInfoMap, long timeout) { - return SaJwtUtil.createToken(loginType, loginId, device, expandInfoMap, timeout, jwtSecretKey()); + public String createTokenValue(Object loginId, String device, long timeout, Map extraData) { + return SaJwtUtil.createToken(loginType, loginId, device, timeout, extraData, jwtSecretKey()); } /** @@ -96,7 +91,7 @@ public class StpLogicJwtForStateless extends StpLogic { loginModel.build(getConfig()); // ------ 2、生成一个token - String tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getExpandInfoMap(), loginModel.getTimeout()); + String tokenValue = createTokenValue(id, loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData()); // 3、在当前会话写入tokenValue setTokenValue(tokenValue, loginModel.getCookieTimeout()); @@ -124,21 +119,6 @@ public class StpLogicJwtForStateless extends StpLogic { } } - @Override - public Object getExpandInfoNotHandle(String tokenValue) { - // 先验证 loginType,如果不符,则视为无效token,返回null - String loginType = SaJwtUtil.getPayloadsNotCheck(tokenValue, jwtSecretKey()).getStr(SaJwtUtil.LOGIN_TYPE); - if(getLoginType().equals(loginType) == false) { - return null; - } - // 获取 expandInfoMap - try { - return SaJwtUtil.getExpandInfo(tokenValue, jwtSecretKey()); - } catch (NotLoginException e) { - return null; - } - } - /** * 会话注销 */ @@ -154,7 +134,15 @@ public class StpLogicJwtForStateless extends StpLogic { SaHolder.getResponse().deleteCookie(getTokenName()); } } - + + /** + * 获取Token携带的扩展信息 + */ + @Override + public Object getExtra(String key) { + return SaJwtUtil.getPayloads(getTokenValue(), jwtSecretKey()).get(key); + } + // ------------------- 过期时间相关 ------------------- diff --git a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java index 03884442..69eede69 100644 --- a/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java +++ b/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForStyle.java @@ -1,5 +1,7 @@ package cn.dev33.satoken.jwt; +import java.util.Map; + import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; @@ -37,12 +39,18 @@ public class StpLogicJwtForStyle extends StpLogic { /** * 创建一个TokenValue - * @param loginId loginId - * @return 生成的tokenValue */ @Override - public String createTokenValue(Object loginId, String device, long timeout) { - return SaJwtUtil.createToken(loginId, jwtSecretKey()); + public String createTokenValue(Object loginId, String device, long timeout, Map extraData) { + return SaJwtUtil.createToken(loginId, extraData, jwtSecretKey()); } - + + /** + * 获取Token携带的扩展信息 + */ + @Override + public Object getExtra(String key) { + return SaJwtUtil.getPayloads(getTokenValue(), jwtSecretKey()).get(key); + } + }