diff --git a/sa-token-doc/oauth2/oauth2-custom-scope.md b/sa-token-doc/oauth2/oauth2-custom-scope.md index e3e6e881..43bcaab3 100644 --- a/sa-token-doc/oauth2/oauth2-custom-scope.md +++ b/sa-token-doc/oauth2/oauth2-custom-scope.md @@ -27,7 +27,7 @@ public SaResult userinfo() { System.out.println("-------- 此Access-Token对应的账号id: " + loginId); // 校验 Access-Token 是否具有权限: userinfo - SaOAuth2Util.checkScope(accessToken, "userinfo"); + SaOAuth2Util.checkAccessTokenScope(accessToken, "userinfo"); // 模拟账号信息 (真实环境需要查询数据库获取信息) Map map = new LinkedHashMap<>(); 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); }