From 203bf304cb7f07e1fb85866248ca4f2ef52ab589 Mon Sep 17 00:00:00 2001 From: wangtao Date: Tue, 3 Sep 2024 15:48:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=9C=A8oidc=E6=A8=A1=E5=BC=8F=E4=B8=8B?= =?UTF-8?q?=EF=BC=8C=E5=A6=82=E6=9E=9C=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=90=BA?= =?UTF-8?q?=E5=B8=A6=E6=9C=89nonce=E9=9A=8F=E6=9C=BA=E6=95=B0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E8=AE=A4=E8=AF=81=E6=9C=8D=E5=8A=A1=E7=AB=AF?= =?UTF-8?q?=E5=9C=A8=E7=94=9F=E6=88=90=E7=9A=84idtoken=E4=B8=AD=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E8=BF=94=E5=9B=9E=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E7=9A=84nonce=E9=9A=8F=E6=9C=BA=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E4=BE=9B=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=BF=9B=E8=A1=8C=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E3=80=82=20=E6=9D=A5=E6=BA=90=EF=BC=9Ahttp://openid.n?= =?UTF-8?q?et/specs/openid-connect-core-1=5F0.html#IDTokenValidation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../satoken/oauth2/consts/SaOAuth2Consts.java | 1 + .../dev33/satoken/oauth2/dao/SaOAuth2Dao.java | 32 +++++++++++++++++++ .../SaOAuth2DataGenerateDefaultImpl.java | 6 +++- .../satoken/oauth2/data/model/CodeModel.java | 19 +++++++++-- .../data/model/request/RequestAuthModel.java | 23 ++++++++++++- .../SaOAuth2DataResolverDefaultImpl.java | 1 + .../scope/handler/OidcScopeHandler.java | 9 +++++- 7 files changed, 86 insertions(+), 5 deletions(-) diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/consts/SaOAuth2Consts.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/consts/SaOAuth2Consts.java index 9637d125..009467c1 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/consts/SaOAuth2Consts.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/consts/SaOAuth2Consts.java @@ -60,6 +60,7 @@ public class SaOAuth2Consts { public static String pwd = "pwd"; public static String build_redirect_uri = "build_redirect_uri"; public static String Authorization = "Authorization"; + public static String nonce = "nonce"; } /** diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2Dao.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2Dao.java index 0c4b3eef..4f4d7856 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2Dao.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2Dao.java @@ -170,6 +170,17 @@ public interface SaOAuth2Dao { } } + /** + * 持久化:nonce-索引 + * @param c . + */ + default void saveCodeNonceIndex(CodeModel c) { + if(c == null || SaFoxUtil.isEmpty(c.nonce)) { + return; + } + getSaTokenDao().set(splicingCodeNonceIndexSaveKey(c.code), c.nonce, SaOAuth2Manager.getServerConfig().getCodeTimeout()); + } + // ------------------- delete数据 @@ -404,6 +415,18 @@ public interface SaOAuth2Dao { return getSaTokenDao().get(splicingStateSaveKey(state)); } + /** + * 获取:nonce + * @param code / + * @return / + */ + default String getNonce(String code) { + if(SaFoxUtil.isEmpty(code)) { + return null; + } + return getSaTokenDao().get(splicingCodeNonceIndexSaveKey(code)); + } + // ------------------- 拼接key @@ -510,6 +533,15 @@ public interface SaOAuth2Dao { return getSaTokenConfig().getTokenName() + ":oauth2:state:" + state; } + /** + * 拼接key:code-nonce 索引 参数持久化 + * @param code 授权码 + * @return key + */ + default String splicingCodeNonceIndexSaveKey(String code) { + return getSaTokenConfig().getTokenName() + ":oauth2:code-nonce-index:" + code; + } + // -------- bean 对象代理 diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/generate/SaOAuth2DataGenerateDefaultImpl.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/generate/SaOAuth2DataGenerateDefaultImpl.java index b9f5186e..d78efc6d 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/generate/SaOAuth2DataGenerateDefaultImpl.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/generate/SaOAuth2DataGenerateDefaultImpl.java @@ -31,6 +31,7 @@ import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception; import cn.dev33.satoken.oauth2.exception.SaOAuth2RefreshTokenException; import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy; import cn.dev33.satoken.util.SaFoxUtil; +import cn.dev33.satoken.util.SaResult; import java.util.LinkedHashMap; import java.util.List; @@ -58,12 +59,15 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate { // 生成新Code String codeValue = SaOAuth2Strategy.instance.createCodeValue.execute(ra.clientId, ra.loginId, ra.scopes); - CodeModel cm = new CodeModel(codeValue, ra.clientId, ra.scopes, ra.loginId, ra.redirectUri); + CodeModel cm = new CodeModel(codeValue, ra.clientId, ra.scopes, ra.loginId, ra.redirectUri, ra.getNonce()); // 保存新Code dao.saveCode(cm); dao.saveCodeIndex(cm); + // 保存code-nonce + dao.saveCodeNonceIndex(cm); + // 返回 return cm; } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/CodeModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/CodeModel.java index 57653f27..2a76c08f 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/CodeModel.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/CodeModel.java @@ -52,6 +52,11 @@ public class CodeModel implements Serializable { * 重定向的地址 */ public String redirectUri; + + /** + * 随机数 + */ + public String nonce; /** * 构建一个 @@ -67,13 +72,14 @@ public class CodeModel implements Serializable { * @param loginId 对应的账号id * @param redirectUri 重定向地址 */ - public CodeModel(String code, String clientId, List scopes, Object loginId, String redirectUri) { + public CodeModel(String code, String clientId, List scopes, Object loginId, String redirectUri, String nonce) { super(); this.code = code; this.clientId = clientId; this.scopes = scopes; this.loginId = loginId; this.redirectUri = redirectUri; + this.nonce = nonce; } public String getCode() { @@ -121,10 +127,19 @@ public class CodeModel implements Serializable { return this; } + public String getNonce() { + return nonce; + } + + public CodeModel setNonce(String nonce) { + this.nonce = nonce; + return this; + } + @Override public String toString() { return "CodeModel [code=" + code + ", clientId=" + clientId + ", scopes=" + scopes + ", loginId=" + loginId - + ", redirectUri=" + redirectUri + "]"; + + ", redirectUri=" + redirectUri + ", nonce=" + nonce + " ]"; } } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/request/RequestAuthModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/request/RequestAuthModel.java index 9837e437..c07d3bf5 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/request/RequestAuthModel.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/model/request/RequestAuthModel.java @@ -62,6 +62,11 @@ public class RequestAuthModel implements Serializable { */ public String state; + /** + * 随机数 + */ + public String nonce; + /** * @return clientId @@ -158,7 +163,23 @@ public class RequestAuthModel implements Serializable { this.state = state; return this; } - + + /** + * @return nonce + */ + public String getNonce() { + return nonce; + } + + /** + * @param nonce 要设置的随机数 + * @return 对象自身 + */ + public RequestAuthModel setNonce(String nonce) { + this.nonce = nonce; + return this; + } + /** * 检查此Model参数是否有效 * @return 对象自身 diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/resolver/SaOAuth2DataResolverDefaultImpl.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/resolver/SaOAuth2DataResolverDefaultImpl.java index 64ade8a6..73c1c970 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/resolver/SaOAuth2DataResolverDefaultImpl.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/resolver/SaOAuth2DataResolverDefaultImpl.java @@ -136,6 +136,7 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver { ra.responseType = req.getParamNotNull(Param.response_type); ra.redirectUri = req.getParamNotNull(Param.redirect_uri); ra.state = req.getParam(Param.state); + ra.nonce = req.getParam(Param.nonce); ra.scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(req.getParam(Param.scope)); ra.loginId = loginId; return ra; diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/handler/OidcScopeHandler.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/handler/OidcScopeHandler.java index 97c70d1d..426e1133 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/handler/OidcScopeHandler.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/handler/OidcScopeHandler.java @@ -22,6 +22,8 @@ import cn.dev33.satoken.jwt.SaJwtUtil; import cn.dev33.satoken.jwt.error.SaJwtErrorCode; import cn.dev33.satoken.jwt.exception.SaJwtException; import cn.dev33.satoken.oauth2.SaOAuth2Manager; +import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts; +import cn.dev33.satoken.oauth2.dao.SaOAuth2Dao; import cn.dev33.satoken.oauth2.data.model.AccessTokenModel; import cn.dev33.satoken.oauth2.data.model.ClientTokenModel; import cn.dev33.satoken.oauth2.data.model.oidc.IdTokenModel; @@ -104,7 +106,12 @@ public class OidcScopeHandler implements SaOAuth2ScopeHandlerInterface { * @return / */ public String getNonce() { - String nonce = SaHolder.getRequest().getParam("nonce"); + String nonce = SaHolder.getRequest().getParam(SaOAuth2Consts.Param.nonce); + if(SaFoxUtil.isEmpty(nonce)) { + //通过code查找nonce + //为了避免其它handler可能会用到nonce,任由其自然过期,只取用不删除 + nonce = SaOAuth2Manager.getDao().getNonce(SaHolder.getRequest().getParam(SaOAuth2Consts.Param.code)); + } if(SaFoxUtil.isEmpty(nonce)) { nonce = SaFoxUtil.getRandomString(32); }