!311 在oidc模式下,如果客户端携带有nonce随机数参数,认证服务端在生成的idtoken中需要返回客户端提交的nonce随机数,供客户端进行校验。

Merge pull request !311 from t_wang/dev
This commit is contained in:
刘潇 2024-09-05 05:30:48 +00:00 committed by Gitee
commit 1fa07884f3
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 86 additions and 5 deletions

View File

@ -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";
}
/**

View File

@ -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;
}
/**
* 拼接keycode-nonce 索引 参数持久化
* @param code 授权码
* @return key
*/
default String splicingCodeNonceIndexSaveKey(String code) {
return getSaTokenConfig().getTokenName() + ":oauth2:code-nonce-index:" + code;
}
// -------- bean 对象代理

View File

@ -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;
}

View File

@ -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<String> scopes, Object loginId, String redirectUri) {
public CodeModel(String code, String clientId, List<String> 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 + " ]";
}
}

View File

@ -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 对象自身

View File

@ -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;

View File

@ -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);
}