From e21928183dde88ca3e9915b3e65406168f38422f Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Fri, 21 Oct 2022 18:19:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=99=BB=E5=BD=95=E5=90=8E?= =?UTF-8?q?=E5=B0=86=20Token=20=E5=86=99=E5=85=A5=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=A4=B4=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dev33/satoken/config/SaTokenConfig.java | 20 +++++ .../satoken/context/model/SaResponse.java | 5 ++ .../cn/dev33/satoken/stp/SaLoginConfig.java | 20 +++-- .../cn/dev33/satoken/stp/SaLoginModel.java | 74 +++++++++++++++++-- .../java/cn/dev33/satoken/stp/StpLogic.java | 34 ++++++++- .../java/cn/dev33/satoken/stp/StpUtil.java | 11 ++- .../java/com/pj/satoken/SaTokenConfigure.java | 20 ++++- 7 files changed, 163 insertions(+), 21 deletions(-) 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 068a4eb2..53026e9a 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 @@ -46,6 +46,9 @@ public class SaTokenConfig implements Serializable { /** 是否尝试从cookie里读取token */ private Boolean isReadCookie = true; + /** 是否在登录后将 Token 写入到响应头 */ + private Boolean isWriteHeader = false; + /** token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) */ private String tokenStyle = "uuid"; @@ -240,6 +243,22 @@ public class SaTokenConfig implements Serializable { return this; } + /** + * @return 是否在登录后将 Token 写入到响应头 + */ + public Boolean getIsWriteHeader() { + return isWriteHeader; + } + + /** + * @param isWriteHeader 是否在登录后将 Token 写入到响应头 + * @return 对象自身 + */ + public SaTokenConfig setIsWriteHeader(Boolean isWriteHeader) { + this.isWriteHeader = isWriteHeader; + return this; + } + /** * @return token风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) */ @@ -462,6 +481,7 @@ public class SaTokenConfig implements Serializable { + ", isReadBody=" + isReadBody + ", isReadHeader=" + isReadHeader + ", isReadCookie=" + isReadCookie + + ", isWriteHeader=" + isWriteHeader + ", tokenStyle=" + tokenStyle + ", dataRefreshPeriod=" + dataRefreshPeriod + ", tokenSessionCheckLogin=" + tokenSessionCheckLogin diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaResponse.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaResponse.java index 9718f9e5..99984369 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaResponse.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaResponse.java @@ -7,6 +7,11 @@ package cn.dev33.satoken.context.model; */ public interface SaResponse { + /** + * 指定前端可以获取到哪些响应头时使用的参数名 + */ + public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers"; + /** * 获取底层源对象 * @return see note diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginConfig.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginConfig.java index 1c70bdca..e25b7ebf 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginConfig.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/SaLoginConfig.java @@ -16,7 +16,7 @@ public class SaLoginConfig { /** * @param device 此次登录的客户端设备类型 - * @return SaLoginModel配置对象 + * @return 登录参数 Model */ public static SaLoginModel setDevice(String device) { return create().setDevice(device); @@ -24,7 +24,7 @@ public class SaLoginConfig { /** * @param isLastingCookie 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) - * @return 对象自身 + * @return 登录参数 Model */ public static SaLoginModel setIsLastingCookie(Boolean isLastingCookie) { return create().setIsLastingCookie(isLastingCookie); @@ -32,7 +32,7 @@ public class SaLoginConfig { /** * @param timeout 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值) - * @return 对象自身 + * @return 登录参数 Model */ public static SaLoginModel setTimeout(long timeout) { return create().setTimeout(timeout); @@ -40,7 +40,7 @@ public class SaLoginConfig { /** * @param extraData 扩展信息(只在jwt模式下生效) - * @return 对象自身 + * @return 登录参数 Model */ public static SaLoginModel setExtraData(Map extraData) { return create().setExtraData(extraData); @@ -48,7 +48,7 @@ public class SaLoginConfig { /** * @param token 预定Token(预定本次登录生成的Token值) - * @return 对象自身 + * @return 登录参数 Model */ public static SaLoginModel setToken(String token) { return create().setToken(token); @@ -58,12 +58,20 @@ public class SaLoginConfig { * 写入扩展数据(只在jwt模式下生效) * @param key 键 * @param value 值 - * @return 对象自身 + * @return 登录参数 Model */ public static SaLoginModel setExtra(String key, Object value) { return create().setExtra(key, value); } + /** + * @param isWriteHeader 是否在登录后将 Token 写入到响应头 + * @return 登录参数 Model + */ + public static SaLoginModel setIsWriteHeader(Boolean isWriteHeader) { + return create().setIsWriteHeader(isWriteHeader); + } + /** * 静态方法获取一个 SaLoginModel 对象 * @return SaLoginModel 对象 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 9b3fe71f..0e32823d 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 @@ -23,7 +23,7 @@ public class SaLoginModel { /** * 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) */ - public Boolean isLastingCookie; + public Boolean isLastingCookie = true; /** * 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值) @@ -39,6 +39,9 @@ public class SaLoginModel { * 预定Token(预定本次登录生成的Token值) */ public String token; + + /** 是否在登录后将 Token 写入到响应头 */ + private Boolean isWriteHeader; /** @@ -58,12 +61,22 @@ public class SaLoginModel { } /** - * @return 参考 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) + * @return 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) */ public Boolean getIsLastingCookie() { return isLastingCookie; } + /** + * @return 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) + */ + public Boolean getIsLastingCookieOrFalse() { + if(isLastingCookie == null) { + return false; + } + return isLastingCookie; + } + /** * @param isLastingCookie 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在) * @return 对象自身 @@ -121,13 +134,45 @@ public class SaLoginModel { return this; } + /** + * @return 是否在登录后将 Token 写入到响应头 + */ + public Boolean getIsWriteHeader() { + return isWriteHeader; + } + + /** + * @return 是否在登录后将 Token 写入到响应头 + */ + public Boolean getIsWriteHeaderOrFalse() { + if(isWriteHeader == null) { + return false; + } + return isWriteHeader; + } + + /** + * @param isWriteHeader 是否在登录后将 Token 写入到响应头 + * @return 对象自身 + */ + public SaLoginModel setIsWriteHeader(Boolean isWriteHeader) { + this.isWriteHeader = isWriteHeader; + return this; + } + /* * toString */ @Override public String toString() { - return "SaLoginModel [device=" + device + ", isLastingCookie=" + isLastingCookie + ", timeout=" + timeout - + ", extraData=" + extraData + ", token=" + token + "]"; + return "SaLoginModel [" + + "device=" + device + + ", isLastingCookie=" + isLastingCookie + + ", timeout=" + timeout + + ", extraData=" + extraData + + ", token=" + token + + ", isWriteHeader=" + isWriteHeader + + "]"; } // ------ 附加方法 @@ -174,9 +219,10 @@ public class SaLoginModel { * @return Cookie时长 */ public int getCookieTimeout() { - if(isLastingCookie == false) { + if(getIsLastingCookieOrFalse() == false) { return -1; } + initTimeout(); if(timeout == SaTokenDao.NEVER_EXPIRE) { return Integer.MAX_VALUE; } @@ -193,6 +239,15 @@ public class SaLoginModel { return device; } + /** + * 初始化 timeout 值 (如果尚未配置timeout,则取全局配置的值) + */ + public void initTimeout() { + if(timeout == null) { + timeout = SaManager.getConfig().getTimeout(); + } + } + /** * 构建对象,初始化默认值 * @return 对象自身 @@ -210,12 +265,15 @@ public class SaLoginModel { // if(device == null) { // device = SaTokenConsts.DEFAULT_LOGIN_DEVICE; // } - if(isLastingCookie == null) { - isLastingCookie = true; - } +// if(isLastingCookie == null) { +// isLastingCookie = true; +// } if(timeout == null) { timeout = config.getTimeout(); } + if(isWriteHeader == null) { + isWriteHeader = config.getIsWriteHeader(); + } return this; } 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 e8e1a625..af308f0e 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 @@ -17,6 +17,7 @@ import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.context.model.SaCookie; import cn.dev33.satoken.context.model.SaRequest; +import cn.dev33.satoken.context.model.SaResponse; import cn.dev33.satoken.context.model.SaStorage; import cn.dev33.satoken.dao.SaTokenDao; import cn.dev33.satoken.exception.ApiDisabledException; @@ -102,7 +103,7 @@ public class StpLogic { * @param tokenValue token值 */ public void setTokenValue(String tokenValue){ - setTokenValue(tokenValue, getConfigOfCookieTimeout()); + setTokenValue(tokenValue, new SaLoginModel().setTimeout(getConfig().getTimeout())); } /** @@ -111,17 +112,31 @@ public class StpLogic { * @param cookieTimeout Cookie存活时间(秒) */ public void setTokenValue(String tokenValue, int cookieTimeout){ + setTokenValue(tokenValue, new SaLoginModel().setTimeout(cookieTimeout)); + } + + /** + * 在当前会话写入当前TokenValue + * @param tokenValue token值 + * @param loginModel 登录参数 + */ + public void setTokenValue(String tokenValue, SaLoginModel loginModel){ if(SaFoxUtil.isEmpty(tokenValue)) { return; } - // 1. 将token保存到[存储器]里 + // 1. 将 Token 保存到 [存储器] 里 setTokenValueToStorage(tokenValue); // 2. 将 Token 保存到 [Cookie] 里 if (getConfig().getIsReadCookie()) { - setTokenValueToCookie(tokenValue, cookieTimeout); + setTokenValueToCookie(tokenValue, loginModel.getCookieTimeout()); + } + + // 3. 将 Token 写入到响应头里 + if(loginModel.getIsWriteHeaderOrFalse()) { + setTokenValueToResponseHeader(tokenValue); } } @@ -164,6 +179,17 @@ public class StpLogic { ; SaHolder.getResponse().addCookie(cookie); } + + /** + * 将 Token 写入到 [响应头] 里 + * @param tokenValue token值 + */ + public void setTokenValueToResponseHeader(String tokenValue){ + String tokenName = getTokenName(); + SaResponse response = SaHolder.getResponse(); + response.setHeader(tokenName, tokenValue); + response.addHeader(SaResponse.ACCESS_CONTROL_EXPOSE_HEADERS, tokenName); + } /** * 获取当前TokenValue @@ -292,7 +318,7 @@ public class StpLogic { String token = createLoginSession(id, loginModel); // 2、在当前客户端注入Token - setTokenValue(token, loginModel.getCookieTimeout()); + setTokenValue(token, loginModel); } /** 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 60d02e10..931d7c3a 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 @@ -83,7 +83,16 @@ public class StpUtil { public static void setTokenValue(String tokenValue, int cookieTimeout){ stpLogic.setTokenValue(tokenValue, cookieTimeout); } - + + /** + * 在当前会话写入当前TokenValue + * @param tokenValue token值 + * @param loginModel 登录参数 + */ + public static void setTokenValue(String tokenValue, SaLoginModel loginModel){ + stpLogic.setTokenValue(tokenValue, loginModel); + } + /** * 获取当前TokenValue * @return 当前tokenValue diff --git a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java index a4a4995e..00ce6931 100644 --- a/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java +++ b/sa-token-demo/sa-token-demo-test/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -8,6 +8,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.filter.SaServletFilter; import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaHttpMethod; +import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.util.SaResult; @@ -51,7 +53,7 @@ public class SaTokenConfigure implements WebMvcConfigurer { }) // 前置函数:在每次认证函数之前执行 - .setBeforeAuth(r -> { + .setBeforeAuth(obj -> { // ---------- 设置一些安全响应头 ---------- SaHolder.getResponse() // 服务器名称 @@ -62,7 +64,21 @@ public class SaTokenConfigure implements WebMvcConfigurer { .setHeader("X-XSS-Protection", "1; mode=block") // 禁用浏览器内容嗅探 .setHeader("X-Content-Type-Options", "nosniff") - ; + + // ---------- 设置跨域响应头 ---------- + // 允许指定域访问跨域资源 + .setHeader("Access-Control-Allow-Origin", "*") + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "*"); + + // 如果是预检请求,则立即返回到前端 + SaRouter.match(SaHttpMethod.OPTIONS) + .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) + .back(); }) ; }