From a5b65fb30e5040ee2d2e43ab04275c2296527e1f Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 11 Jun 2021 01:05:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E5=90=88=20jwt=20=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E4=BB=A4=E7=89=8C=E9=89=B4=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/dev33/satoken/SaManager.java | 6 +- .../dev33/satoken/config/SaTokenConfig.java | 28 ++++- .../dev33/satoken/temp/SaTempDefaultImpl.java | 10 ++ .../dev33/satoken/temp/SaTempInterface.java | 9 +- .../temp/SaTempInterfaceDefaultImpl.java | 10 -- .../cn/dev33/satoken/temp/SaTempUtil.java | 2 +- .../sa-token-demo-springboot/pom.xml | 2 +- sa-token-doc/doc/start/download.md | 4 +- sa-token-doc/doc/use/config.md | 1 + sa-token-plugin/pom.xml | 1 + sa-token-plugin/sa-token-temp-jwt/.gitignore | 12 ++ sa-token-plugin/sa-token-temp-jwt/pom.xml | 40 ++++++ .../cn/dev33/satoken/temp/jwt/SaJwtUtil.java | 114 ++++++++++++++++++ .../dev33/satoken/temp/jwt/SaTempForJwt.java | 51 ++++++++ .../main/resources/META-INF/spring.factories | 1 + .../spring/SaTokenSpringAutowired.java | 11 ++ .../cn/dev33/satoken/solon/XPluginImp.java | 14 ++- .../spring/SaTokenSpringAutowired.java | 11 ++ .../pj/test/SaTokenSpringBootStarterTest.java | 1 - 19 files changed, 304 insertions(+), 24 deletions(-) create mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempDefaultImpl.java delete mode 100644 sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterfaceDefaultImpl.java create mode 100644 sa-token-plugin/sa-token-temp-jwt/.gitignore create mode 100644 sa-token-plugin/sa-token-temp-jwt/pom.xml create mode 100644 sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaJwtUtil.java create mode 100644 sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaTempForJwt.java create mode 100644 sa-token-plugin/sa-token-temp-jwt/src/main/resources/META-INF/spring.factories 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 9b9d1e38..a7b7e770 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 @@ -19,7 +19,7 @@ import cn.dev33.satoken.stp.StpInterfaceDefaultImpl; import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.temp.SaTempInterface; -import cn.dev33.satoken.temp.SaTempInterfaceDefaultImpl; +import cn.dev33.satoken.temp.SaTempDefaultImpl; import cn.dev33.satoken.util.SaFoxUtil; /** @@ -146,7 +146,7 @@ public class SaManager { } /** - * 临时验证模块 Bean + * 临时令牌验证模块 Bean */ private static SaTempInterface saTemp; public static void setSaTemp(SaTempInterface saTemp) { @@ -156,7 +156,7 @@ public class SaManager { if (saTemp == null) { synchronized (SaManager.class) { if (saTemp == null) { - setSaTemp(new SaTempInterfaceDefaultImpl()); + setSaTemp(new SaTempDefaultImpl()); } } } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java index af29cd17..b2c45e67 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/config/SaTokenConfig.java @@ -61,6 +61,11 @@ public class SaTokenConfig { /** 是否打印操作日志 */ private Boolean isLog = false; + /** + * jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效) + */ + private String jwtSecretKey; + /** * @return token名称 (同时也是cookie名称) @@ -315,6 +320,7 @@ public class SaTokenConfig { /** * @param isLog 是否打印操作日志 + * @return 对象自身 */ public SaTokenConfig setIsLog(Boolean isLog) { this.isLog = isLog; @@ -322,7 +328,23 @@ public class SaTokenConfig { } /** - * toString() + * @return jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效) + */ + public String getJwtSecretKey() { + return jwtSecretKey; + } + + /** + * @param jwtSecretKey jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效) + * @return 对象自身 + */ + public SaTokenConfig setJwtSecretKey(String jwtSecretKey) { + this.jwtSecretKey = jwtSecretKey; + return this; + } + + /** + * toString() */ @Override public String toString() { @@ -331,9 +353,11 @@ public class SaTokenConfig { + isReadBody + ", isReadHead=" + isReadHead + ", isReadCookie=" + isReadCookie + ", tokenStyle=" + tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin=" + tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain - + ", tokenPrefix=" + tokenPrefix + ", isV=" + isV + ", isLog=" + isLog + "]"; + + ", tokenPrefix=" + tokenPrefix + ", isV=" + isV + ", isLog=" + isLog + ", jwtSecretKey=" + + jwtSecretKey + "]"; } + diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempDefaultImpl.java new file mode 100644 index 00000000..e0ec0cbb --- /dev/null +++ b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempDefaultImpl.java @@ -0,0 +1,10 @@ +package cn.dev33.satoken.temp; + +/** + * Sa-Token 临时令牌验证模块 默认实现类 + * @author kong + * + */ +public class SaTempDefaultImpl implements SaTempInterface { + +} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java index e6135e22..e2a01f19 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterface.java @@ -4,7 +4,7 @@ import cn.dev33.satoken.SaManager; import cn.dev33.satoken.util.SaFoxUtil; /** - * Sa-Token 临时验证模块接口 + * Sa-Token 临时令牌验证模块接口 * @author kong * */ @@ -69,4 +69,11 @@ public interface SaTempInterface { return SaManager.getConfig().getTokenName() + ":temp-token:" + token; } + /** + * @return jwt秘钥 (只有集成 sa-token-temp-jwt 模块时此参数才会生效) + */ + public default String getJwtSecretKey() { + return null; + } + } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterfaceDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterfaceDefaultImpl.java deleted file mode 100644 index ccf3ec95..00000000 --- a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempInterfaceDefaultImpl.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.dev33.satoken.temp; - -/** - * Sa-Token 临时验证模块 逻辑 - * @author kong - * - */ -public class SaTempInterfaceDefaultImpl implements SaTempInterface { - -} diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java index f5752d59..5c7e4fa9 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/temp/SaTempUtil.java @@ -3,7 +3,7 @@ package cn.dev33.satoken.temp; import cn.dev33.satoken.SaManager; /** - * Sa-Token 临时验证模块 + * Sa-Token 临时验证令牌模块 * @author kong * */ diff --git a/sa-token-demo/sa-token-demo-springboot/pom.xml b/sa-token-demo/sa-token-demo-springboot/pom.xml index 991dca39..a0333a56 100644 --- a/sa-token-demo/sa-token-demo-springboot/pom.xml +++ b/sa-token-demo/sa-token-demo-springboot/pom.xml @@ -37,7 +37,7 @@ sa-token-spring-boot-starter ${sa-token-version} - + sa-token-quick-login + sa-token-temp-jwt \ No newline at end of file diff --git a/sa-token-plugin/sa-token-temp-jwt/.gitignore b/sa-token-plugin/sa-token-temp-jwt/.gitignore new file mode 100644 index 00000000..f56feec7 --- /dev/null +++ b/sa-token-plugin/sa-token-temp-jwt/.gitignore @@ -0,0 +1,12 @@ +target/ + +node_modules/ +bin/ +.settings/ +unpackage/ +.classpath +.project + +.factorypath + +.idea/ \ No newline at end of file diff --git a/sa-token-plugin/sa-token-temp-jwt/pom.xml b/sa-token-plugin/sa-token-temp-jwt/pom.xml new file mode 100644 index 00000000..2e5b776b --- /dev/null +++ b/sa-token-plugin/sa-token-temp-jwt/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + + cn.dev33 + sa-token-plugin + 1.19.0 + + jar + + sa-token-temp-jwt + sa-token-temp-jwt + sa-token-temp-jwt + + + + + cn.dev33 + sa-token-core + ${sa-token-version} + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + org.springframework.boot + spring-boot-configuration-processor + 2.0.0.RELEASE + true + + + + diff --git a/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaJwtUtil.java b/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaJwtUtil.java new file mode 100644 index 00000000..3c4c0297 --- /dev/null +++ b/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaJwtUtil.java @@ -0,0 +1,114 @@ +package cn.dev33.satoken.temp.jwt; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.exception.SaTokenException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +/** + * jwt操作工具类 + * @author kong + * + */ +public class SaJwtUtil { + + /** + * key: value + */ + public static final String KEY_VALUE = "value"; + + /** + * key: 有效期 (时间戳) + */ + public static final String KEY_EFF = "eff"; + + /** 当有效期被设为此值时,代表永不过期 */ + public static final long NEVER_EXPIRE = SaTokenDao.NEVER_EXPIRE; + + /** + * 根据指定值创建 jwt-token + * @param value 要保存的值 + * @param timeout token有效期 (单位 秒) + * @param keyt 秘钥 + * @return jwt-token + */ + public static String createToken(Object value, long timeout, String keyt) { + // 计算eff有效期 + long eff = timeout; + if(timeout != NEVER_EXPIRE) { + eff = timeout * 1000 + System.currentTimeMillis(); + } + // 在这里你可以使用官方提供的claim方法构建载荷,也可以使用setPayload自定义载荷,但是两者不可一起使用 + JwtBuilder builder = Jwts.builder() + // .setHeaderParam("typ", "JWT") + .claim(KEY_VALUE, value) + .claim(KEY_EFF, eff) + .signWith(SignatureAlgorithm.HS256, keyt.getBytes()); + // 生成jwt-token + return builder.compact(); + } + + /** + * 从一个 jwt-token 解析出载荷 + * @param jwtToken JwtToken值 + * @param keyt 秘钥 + * @return Claims对象 + */ + public static Claims parseToken(String jwtToken, String keyt) { + // 解析出载荷 + Claims claims = Jwts.parser() + .setSigningKey(keyt.getBytes()) + .parseClaimsJws(jwtToken).getBody(); + // 返回 + return claims; + } + + /** + * 从一个 jwt-token 解析出载荷, 并取出数据 + * @param jwtToken JwtToken值 + * @param keyt 秘钥 + * @return 值 + */ + public static Object getValue(String jwtToken, String keyt) { + // 取出数据 + Claims claims = parseToken(jwtToken, keyt); + + // 验证是否超时 + Long eff = claims.get(KEY_EFF, Long.class); + if((eff == null || eff < System.currentTimeMillis()) && eff != NEVER_EXPIRE) { + throw new SaTokenException("Token已超时"); + } + + // 获取数据 + return claims.get(KEY_VALUE); + } + + /** + * 从一个 jwt-token 解析出载荷, 并取出其剩余有效期 + * @param jwtToken JwtToken值 + * @param keyt 秘钥 + * @return 值 + */ + public static long getTimeout(String jwtToken, String keyt) { + // 取出数据 + Claims claims = parseToken(jwtToken, keyt); + + // 验证是否超时 + Long eff = claims.get(KEY_EFF, Long.class); + + // 永不过期 + if(eff == NEVER_EXPIRE) { + return NEVER_EXPIRE; + } + // 已经超时 + if(eff == null || eff < System.currentTimeMillis()) { + return SaTokenDao.NOT_VALUE_EXPIRE; + } + + // 计算timeout + return (eff - System.currentTimeMillis()) / 1000; + } + +} diff --git a/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaTempForJwt.java b/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaTempForJwt.java new file mode 100644 index 00000000..60c157fc --- /dev/null +++ b/sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaTempForJwt.java @@ -0,0 +1,51 @@ +package cn.dev33.satoken.temp.jwt; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.temp.SaTempInterface; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * Sa-Token 临时令牌验证模块接口 JWT实现类 + * @author kong + * + */ +public class SaTempForJwt implements SaTempInterface { + + /** + * 根据value创建一个token + */ + public String createToken(Object value, long timeout) { + String token = SaJwtUtil.createToken(value, timeout, getJwtSecretKey()); + return token; + } + + /** + * 解析token获取value + */ + public Object parseToken(String token) { + Object value = SaJwtUtil.getValue(token, getJwtSecretKey()); + return value; + } + + /** + * 返回指定token的剩余有效期,单位:秒 + */ + public long getTimeout(String token) { + long timeout = SaJwtUtil.getTimeout(token, getJwtSecretKey()); + return timeout; + } + + /** + * 获取jwt秘钥 + * @return jwt秘钥 + */ + public String getJwtSecretKey() { + String jwtSecretKey = SaManager.getConfig().getJwtSecretKey(); + if(SaFoxUtil.isEmpty(jwtSecretKey)) { + throw new SaTokenException("请配置:jwtSecretKey"); + } + return jwtSecretKey; + } + +} diff --git a/sa-token-plugin/sa-token-temp-jwt/src/main/resources/META-INF/spring.factories b/sa-token-plugin/sa-token-temp-jwt/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..0c16a1f2 --- /dev/null +++ b/sa-token-plugin/sa-token-temp-jwt/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.dev33.satoken.temp.jwt.SaTempForJwt \ No newline at end of file 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 4ccb0f99..e3fa1613 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 @@ -15,6 +15,7 @@ import cn.dev33.satoken.context.SaTokenContextForThreadLocal; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.temp.SaTempInterface; /** * 利用spring的自动装配来加载开发者重写的Bean @@ -113,6 +114,16 @@ public class SaTokenSpringAutowired { public void setSaTokenListener(SaTokenListener saTokenListener) { SaManager.setSaTokenListener(saTokenListener); } + + /** + * 注入临时令牌验证模块 Bean + * + * @param saTemp saTemp对象 + */ + @Autowired(required = false) + public void setSaTemp(SaTempInterface saTemp) { + SaManager.setSaTemp(saTemp); + } /** * 利用自动注入特性,获取Spring框架内部使用的路由匹配器 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 64892b73..1fe41a55 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 @@ -16,6 +16,7 @@ import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.solon.integration.SaContextForSolon; import cn.dev33.satoken.solon.integration.SaTokenMethodInterceptor; import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.temp.SaTempInterface; /** * @author noear @@ -39,25 +40,30 @@ public class XPluginImp implements Plugin { //注入容器交互Bean SaManager.setSaTokenContext(new SaContextForSolon()); - //注入侦听器Bean + // 注入侦听器 Bean Aop.getAsyn(SaTokenListener.class, bw->{ SaManager.setSaTokenListener(bw.raw()); }); - //注入框架行为Bean + // 注入框架行为 Bean Aop.getAsyn(SaTokenAction.class, bw->{ SaManager.setSaTokenAction(bw.raw()); }); - //注入权限认证Bean + // 注入权限认证 Bean Aop.getAsyn(StpInterface.class, bw->{ SaManager.setStpInterface(bw.raw()); }); - //注入持久化Bean + // 注入持久化 Bean Aop.getAsyn(SaTokenDao.class, bw->{ SaManager.setSaTokenDao(bw.raw()); }); + + // 临时令牌验证模块 Bean + Aop.getAsyn(SaTempInterface.class, bw->{ + SaManager.setSaTemp(bw.raw()); + }); } } 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 2d313e63..117f5534 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 @@ -14,6 +14,7 @@ import cn.dev33.satoken.context.SaTokenContext; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.temp.SaTempInterface; /** * 利用spring的自动装配来加载开发者重写的Bean @@ -105,6 +106,16 @@ public class SaTokenSpringAutowired { SaManager.setSaTokenListener(saTokenListener); } + /** + * 注入临时令牌验证模块 Bean + * + * @param saTemp saTemp对象 + */ + @Autowired(required = false) + public void setSaTemp(SaTempInterface saTemp) { + SaManager.setSaTemp(saTemp); + } + /** * 利用自动注入特性,获取Spring框架内部使用的路由匹配器 * diff --git a/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java index 38d03358..3f7a0afd 100644 --- a/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java +++ b/sa-token-starter/sa-token-spring-boot-starter/src/test/java/com/pj/test/SaTokenSpringBootStarterTest.java @@ -177,7 +177,6 @@ public class SaTokenSpringBootStarterTest { // 解析token String value = SaTempUtil.parseToken(token, String.class); - System.out.println(value); Assert.assertEquals(value, "group-1014"); // 过期时间