1
0
mirror of synced 2026-05-22 14:43:15 +00:00

refactor(oauth2): 优化调整 sa-token-oauth2 模块代码结构及注释

This commit is contained in:
click33
2025-05-14 03:30:31 +08:00
parent 0ed0c277df
commit 5b3a64b9fc
31 changed files with 765 additions and 564 deletions
@@ -33,19 +33,42 @@ public class SaOAuth2OidcConfig implements Serializable {
/** idToken 有效期(单位秒) 默认十分钟 */
public long idTokenTimeout = 60 * 10;
/**
* 获取 iss 值,如不配置则自动计算
*
* @return /
*/
public String getIss() {
return iss;
return this.iss;
}
/**
* 设置 iss 值,如不配置则自动计算
*
* @param iss /
* @return 对象自身
*/
public SaOAuth2OidcConfig setIss(String iss) {
this.iss = iss;
return this;
}
/**
* 获取 idToken 有效期(单位秒) 默认十分钟
*
* @return /
*/
public long getIdTokenTimeout() {
return idTokenTimeout;
return this.idTokenTimeout;
}
/**
* 设置 idToken 有效期(单位秒) 默认十分钟
*
* @param idTokenTimeout /
* @return 对象自身
*/
public SaOAuth2OidcConfig setIdTokenTimeout(long idTokenTimeout) {
this.idTokenTimeout = idTokenTimeout;
return this;
@@ -44,24 +44,18 @@ public class SaOAuth2ServerConfig implements Serializable {
/** 是否打开模式:凭证式(Client Credentials */
public Boolean enableClientCredentials = true;
/** 是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token */
public Boolean isNewRefresh = false;
/** Code授权码 保存的时间(单位:秒) 默认五分钟 */
public long codeTimeout = 60 * 5;
/** Access-Token 保存的时间(单位:秒) 默认两个小时 */
/** 全局默认配置所有应用:Access-Token 保存的时间(单位:秒) 默认两个小时 */
public long accessTokenTimeout = 60 * 60 * 2;
/** Refresh-Token 保存的时间(单位:秒) 默认30 天 */
/** 全局默认配置所有应用:Refresh-Token 保存的时间(单位:秒) 默认30 天 */
public long refreshTokenTimeout = 60 * 60 * 24 * 30;
/** Client-Token 保存的时间(单位:秒) 默认两个小时 */
/** 全局默认配置所有应用:Client-Token 保存的时间(单位:秒) 默认两个小时 */
public long clientTokenTimeout = 60 * 60 * 2;
/** Lower-Client-Token 保存的时间(单位:秒) 默认为 -1,代表延续 Client-Token 有效期 */
public long lowerClientTokenTimeout = -1;
/** 全局默认配置所有应用:单个应用单个用户最多同时存在的 Access-Token 数量 */
public int maxAccessTokenCount = 12;
@@ -71,6 +65,9 @@ public class SaOAuth2ServerConfig implements Serializable {
/** 全局默认配置所有应用:单个应用最多同时存在的 Client-Token 数量 */
public int maxClientTokenCount = 12;
/** 全局默认配置所有应用:是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token */
public Boolean isNewRefresh = false;
/** 默认 openid 生成算法中使用的摘要前缀 */
public String openidDigestPrefix = SaOAuth2Consts.OPENID_DEFAULT_DIGEST_PREFIX;
@@ -83,7 +80,7 @@ public class SaOAuth2ServerConfig implements Serializable {
/** 指定低级权限,多个用逗号隔开 */
public String lowerScope;
/** 模式4是否返回 AccessToken 字段 */
/** 模式4是否返回 AccessToken 字段,以使其更符合 OAuth2 RFC 规范 */
public Boolean mode4ReturnAccessToken = false;
/** 是否在返回值中隐藏默认的状态字段 (code、msg、data) */
@@ -115,15 +112,17 @@ public class SaOAuth2ServerConfig implements Serializable {
// get set
/**
* @return enableCode
* 是否打开模式:授权码(Authorization Code
* @return enableAuthorizationCode
*/
public Boolean getEnableAuthorizationCode() {
return enableAuthorizationCode;
}
/**
* @param enableAuthorizationCode 要设置的 enableAuthorizationCode
* @return /
* 设置是否打开模式:授权码(Authorization Code
* @param enableAuthorizationCode 是否开启
* @return 对象自身
*/
public SaOAuth2ServerConfig setEnableAuthorizationCode(Boolean enableAuthorizationCode) {
this.enableAuthorizationCode = enableAuthorizationCode;
@@ -131,6 +130,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 是否打开模式:隐藏式(Implicit)
* @return enableImplicit
*/
public Boolean getEnableImplicit() {
@@ -138,8 +138,9 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param enableImplicit 要设置的 enableImplicit
* @return /
* 设置是否打开模式:隐藏式(Implicit
* @param enableImplicit 是否开启
* @return 对象自身
*/
public SaOAuth2ServerConfig setEnableImplicit(Boolean enableImplicit) {
this.enableImplicit = enableImplicit;
@@ -147,6 +148,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 是否打开模式:密码式(Password)
* @return enablePassword
*/
public Boolean getEnablePassword() {
@@ -154,7 +156,9 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param enablePassword 要设置的 enablePassword
* 设置是否打开模式:密码式(Password
* @param enablePassword 是否开启
* @return 对象自身
*/
public SaOAuth2ServerConfig setEnablePassword(Boolean enablePassword) {
this.enablePassword = enablePassword;
@@ -162,6 +166,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 是否打开模式:凭证式(Client Credentials
* @return enableClientCredentials
*/
public Boolean getEnableClientCredentials() {
@@ -169,8 +174,9 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param enableClientCredentials 要设置的 enableClientCredentials
* @return /
* 设置是否打开模式:凭证式(Client Credentials
* @param enableClientCredentials 是否开启
* @return 对象自身
*/
public SaOAuth2ServerConfig setEnableClientCredentials(Boolean enableClientCredentials) {
this.enableClientCredentials = enableClientCredentials;
@@ -178,6 +184,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 全局默认配置所有应用:是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token
* @return isNewRefresh
*/
public Boolean getIsNewRefresh() {
@@ -185,8 +192,9 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param isNewRefresh 要设置的 isNewRefresh
* @return /
* 全局默认配置所有应用:设置是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token
* @param isNewRefresh 是否开启
* @return 对象自身
*/
public SaOAuth2ServerConfig setIsNewRefresh(Boolean isNewRefresh) {
this.isNewRefresh = isNewRefresh;
@@ -194,6 +202,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* Code授权码 保存的时间(单位:秒) 默认五分钟
* @return codeTimeout
*/
public long getCodeTimeout() {
@@ -201,7 +210,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param codeTimeout 要设置的 codeTimeout
* 设置Code授权码保存的时间(单位:秒)
* @param codeTimeout 保存时间(秒)
* @return 对象自身
*/
public SaOAuth2ServerConfig setCodeTimeout(long codeTimeout) {
@@ -210,6 +220,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 全局默认配置所有应用:Access-Token 保存的时间(单位:秒) 默认两个小时
* @return accessTokenTimeout
*/
public long getAccessTokenTimeout() {
@@ -217,7 +228,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param accessTokenTimeout 要设置的 accessTokenTimeout
* 全局默认配置所有应用:设置Access-Token保存的时间(单位:秒)
* @param accessTokenTimeout 保存时间(秒)
* @return 对象自身
*/
public SaOAuth2ServerConfig setAccessTokenTimeout(long accessTokenTimeout) {
@@ -226,6 +238,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 全局默认配置所有应用:Refresh-Token 保存的时间(单位:秒) 默认30天
* @return refreshTokenTimeout
*/
public long getRefreshTokenTimeout() {
@@ -233,7 +246,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param refreshTokenTimeout 要设置的 refreshTokenTimeout
* 全局默认配置所有应用:设置Refresh-Token保存的时间(单位:秒)
* @param refreshTokenTimeout 保存时间(秒)
* @return 对象自身
*/
public SaOAuth2ServerConfig setRefreshTokenTimeout(long refreshTokenTimeout) {
@@ -242,6 +256,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 全局默认配置所有应用:Client-Token 保存的时间(单位:秒) 默认两个小时
* @return clientTokenTimeout
*/
public long getClientTokenTimeout() {
@@ -249,7 +264,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param clientTokenTimeout 要设置的 clientTokenTimeout
* 全局默认配置所有应用:设置Client-Token保存的时间(单位:秒)
* @param clientTokenTimeout 保存时间(秒)
* @return 对象自身
*/
public SaOAuth2ServerConfig setClientTokenTimeout(long clientTokenTimeout) {
@@ -258,22 +274,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @return lowerClientTokenTimeout
*/
public long getLowerClientTokenTimeout() {
return lowerClientTokenTimeout;
}
/**
* @param lowerClientTokenTimeout 要设置的 lowerClientTokenTimeout
* @return 对象自身
*/
public SaOAuth2ServerConfig setLowerClientTokenTimeout(long lowerClientTokenTimeout) {
this.lowerClientTokenTimeout = lowerClientTokenTimeout;
return this;
}
/**
* 全局默认配置所有应用:单个应用单个用户最多同时存在的 Access-Token 数量
* @return maxAccessTokenCount
*/
public int getMaxAccessTokenCount() {
@@ -281,7 +282,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param maxAccessTokenCount 要设置的 maxAccessTokenCount
* 设置单个应用单个用户最多同时存在的 Access-Token 数量
* @param maxAccessTokenCount 最大数量
* @return 对象自身
*/
public SaOAuth2ServerConfig setMaxAccessTokenCount(int maxAccessTokenCount) {
@@ -291,15 +293,15 @@ public class SaOAuth2ServerConfig implements Serializable {
/**
* 全局默认配置所有应用:单个应用单个用户最多同时存在的 Refresh-Token 数量
* @return /
* @return maxRefreshTokenCount
*/
public int getMaxRefreshTokenCount() {
return maxRefreshTokenCount;
}
/**
* 全局默认配置所有应用:单个应用单个用户最多同时存在的 Refresh-Token 数量
* @param maxRefreshTokenCount /
* 设置单个应用单个用户最多同时存在的 Refresh-Token 数量
* @param maxRefreshTokenCount 最大数量
* @return 对象自身
*/
public SaOAuth2ServerConfig setMaxRefreshTokenCount(int maxRefreshTokenCount) {
@@ -308,16 +310,16 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 全局默认配置所有应用:单个应用单个用户最多同时存在的 Client-Token 数量
* @return /
* 全局默认配置所有应用:单个应用最多同时存在的 Client-Token 数量
* @return maxClientTokenCount
*/
public int getMaxClientTokenCount() {
return maxClientTokenCount;
}
/**
* 全局默认配置所有应用:单个应用单个用户最多同时存在的 Client-Token 数量
* @param maxClientTokenCount /
* 设置单个应用最多同时存在的 Client-Token 数量
* @param maxClientTokenCount 最大数量
* @return 对象自身
*/
public SaOAuth2ServerConfig setMaxClientTokenCount(int maxClientTokenCount) {
@@ -326,6 +328,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 默认 openid 生成算法中使用的摘要前缀
* @return openidDigestPrefix
*/
public String getOpenidDigestPrefix() {
@@ -333,7 +336,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param openidDigestPrefix 要设置的 openidDigestPrefix
* 设置默认 openid 生成算法中使用的摘要前缀
* @param openidDigestPrefix 摘要前缀
* @return 对象自身
*/
public SaOAuth2ServerConfig setOpenidDigestPrefix(String openidDigestPrefix) {
@@ -342,6 +346,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 默认 unionid 生成算法中使用的摘要前缀
* @return unionidDigestPrefix
*/
public String getUnionidDigestPrefix() {
@@ -349,7 +354,8 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param unionidDigestPrefix 要设置的 unionidDigestPrefix
* 设置默认 unionid 生成算法中使用的摘要前缀
* @param unionidDigestPrefix 摘要前缀
* @return 对象自身
*/
public SaOAuth2ServerConfig setUnionidDigestPrefix(String unionidDigestPrefix) {
@@ -358,19 +364,17 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 获取 指定高级权限,多个用逗号隔开
*
* @return higherScope 指定高级权限,多个用逗号隔开
* 指定高级权限,多个用逗号隔开
* @return higherScope
*/
public String getHigherScope() {
return this.higherScope;
return higherScope;
}
/**
* 设置 指定高级权限,多个用逗号隔开
*
* @param higherScope 指定高级权限,多个用逗号隔开
* @return /
* 设置高级权限,多个用逗号隔开
* @param higherScope 权限字符串
* @return 对象自身
*/
public SaOAuth2ServerConfig setHigherScope(String higherScope) {
this.higherScope = higherScope;
@@ -378,19 +382,17 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 获取 指定低级权限,多个用逗号隔开
*
* @return lowerScope 指定低级权限,多个用逗号隔开
* 指定低级权限,多个用逗号隔开
* @return lowerScope
*/
public String getLowerScope() {
return this.lowerScope;
return lowerScope;
}
/**
* 设置 指定低级权限,多个用逗号隔开
*
* @param lowerScope 指定低级权限,多个用逗号隔开
* @return /
* 设置低级权限,多个用逗号隔开
* @param lowerScope 权限字符串
* @return 对象自身
*/
public SaOAuth2ServerConfig setLowerScope(String lowerScope) {
this.lowerScope = lowerScope;
@@ -398,6 +400,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 模式4是否返回 AccessToken 字段,以使其更符合 OAuth2 RFC 规范
* @return mode4ReturnAccessToken
*/
public Boolean getMode4ReturnAccessToken() {
@@ -405,7 +408,9 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param mode4ReturnAccessToken 要设置的 mode4ReturnAccessToken
* 设置模式4是否返回 AccessToken 字段,以使其更符合 OAuth2 RFC 规范
* @param mode4ReturnAccessToken 是否返回
* @return 对象自身
*/
public SaOAuth2ServerConfig setMode4ReturnAccessToken(Boolean mode4ReturnAccessToken) {
this.mode4ReturnAccessToken = mode4ReturnAccessToken;
@@ -413,6 +418,7 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 是否在返回值中隐藏默认的状态字段 (code、msg、data)
* @return hideStatusField
*/
public Boolean getHideStatusField() {
@@ -420,7 +426,9 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* @param hideStatusField 要设置的 hideStatusField
* 设置是否在返回值中隐藏默认的状态字段 (code、msg、data)
* @param hideStatusField 是否隐藏
* @return 对象自身
*/
public SaOAuth2ServerConfig setHideStatusField(Boolean hideStatusField) {
this.hideStatusField = hideStatusField;
@@ -428,19 +436,17 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 获取 oidc 相关配置
*
* @return oidc 相关配置
* 获取oidc相关配置
* @return oidc配置对象
*/
public SaOAuth2OidcConfig getOidc() {
return this.oidc;
return oidc;
}
/**
* 设置 oidc 相关配置
*
* @param oidc /
* @return /
* 设置oidc相关配置
* @param oidc oidc配置对象
* @return 对象自身
*/
public SaOAuth2ServerConfig setOidc(SaOAuth2OidcConfig oidc) {
this.oidc = oidc;
@@ -448,16 +454,17 @@ public class SaOAuth2ServerConfig implements Serializable {
}
/**
* 获取 client 列表
* @return /
* 获取client列表
* @return client列表
*/
public Map<String, SaClientModel> getClients() {
return clients;
}
/**
* 写入 client 列表
* @return /
* 设置client列表
* @param clients client列表
* @return 对象自身
*/
public SaOAuth2ServerConfig setClients(Map<String, SaClientModel> clients) {
this.clients = clients;
@@ -466,7 +473,7 @@ public class SaOAuth2ServerConfig implements Serializable {
@Override
public String toString() {
return "SaOAuth2ServerConfig{" +
return "SaOAuth2ServerConfig {" +
"enableAuthorizationCode=" + enableAuthorizationCode +
", enableImplicit=" + enableImplicit +
", enablePassword=" + enablePassword +
@@ -476,20 +483,19 @@ public class SaOAuth2ServerConfig implements Serializable {
", accessTokenTimeout=" + accessTokenTimeout +
", refreshTokenTimeout=" + refreshTokenTimeout +
", clientTokenTimeout=" + clientTokenTimeout +
", lowerClientTokenTimeout=" + lowerClientTokenTimeout +
", maxAccessTokenCount=" + maxAccessTokenCount +
", maxRefreshTokenCount=" + maxRefreshTokenCount +
", maxClientTokenCount=" + maxClientTokenCount +
", openidDigestPrefix='" + openidDigestPrefix +
", unionidDigestPrefix='" + unionidDigestPrefix +
", higherScope='" + higherScope +
", lowerScope='" + lowerScope +
", mode4ReturnAccessToken='" + mode4ReturnAccessToken +
", hideStatusField='" + hideStatusField +
", oidc='" + oidc +
", openidDigestPrefix=" + openidDigestPrefix +
", unionidDigestPrefix=" + unionidDigestPrefix +
", higherScope=" + higherScope +
", lowerScope=" + lowerScope +
", mode4ReturnAccessToken=" + mode4ReturnAccessToken +
", hideStatusField=" + hideStatusField +
", oidc=" + oidc +
", clients=" + clients +
'}';
}
}
@@ -27,23 +27,26 @@ import cn.dev33.satoken.oauth2.data.model.RefreshTokenModel;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.raw.SaRawSessionDelegator;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaTtlMethods;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static cn.dev33.satoken.oauth2.template.SaOAuth2Util.checkClientModel;
/**
* Sa-Token OAuth2 数据持久层
* Sa-Token OAuth2 数据持久层 (在 SaTokenDao 之上再封装一层,方便 OAuth2 模块整体的数据读写操作)
*
* @author click33
* @since 1.39.0
*/
public class SaOAuth2Dao {
public class SaOAuth2Dao implements SaTtlMethods {
// ------------------- 索引操作公共代码
/**
* Raw Session 读写委托
* Raw Session 读写委托 (存储 Access-Token、Refresh-Token、Client-Token 索引)
*/
public SaRawSessionDelegator oauth2RSD = new SaRawSessionDelegator("oauth2");
@@ -63,10 +66,11 @@ public class SaOAuth2Dao {
public static final String CLIENT_TOKEN_MAP = "__HD_CLIENT_TOKEN_MAP";
/**
* 获取 Access-Token 索引 RawSession
* 获取:保存 Access-Token 索引时使用的 RawSession
*
* @param clientId 应用 id
* @param loginId 账号 id
* @param isCreate 如果尚未创建,是否理解创建
* @param isCreate 如果尚未创建,是否立即创建
* @return /
*/
protected SaSession getRawSessionByAccessToken(String clientId, Object loginId, boolean isCreate) {
@@ -75,10 +79,11 @@ public class SaOAuth2Dao {
}
/**
* 获取 refresh_token 索引 RawSession
* 获取:保存 Refresh-Token 索引时使用的 RawSession
*
* @param clientId 应用 id
* @param loginId 账号 id
* @param isCreate 如果尚未创建,是否理解创建
* @param isCreate 如果尚未创建,是否立即创建
* @return /
*/
protected SaSession getRawSessionByRefreshToken(String clientId, Object loginId, boolean isCreate) {
@@ -87,9 +92,10 @@ public class SaOAuth2Dao {
}
/**
* 获取 client_token 索引 RawSession
* 获取:保存 Client-Token 索引时使用的 RawSession
*
* @param clientId 应用 id
* @param isCreate 如果尚未创建,是否理解创建
* @param isCreate 如果尚未创建,是否立即创建
* @return /
*/
protected SaSession getRawSessionByClientToken(String clientId, boolean isCreate) {
@@ -98,7 +104,7 @@ public class SaOAuth2Dao {
}
/**
* 在 RawSession 上添加 token 索引
* 在 RawSession 上添加 token 索引,并完整调整索引列表
*
* @param session 待操作的 RawSession
* @param tokenIndexMapSaveKey 在 session 上保存 token 索引列表使用的 key
@@ -107,19 +113,19 @@ public class SaOAuth2Dao {
* @param maxTokenCount 允许的最多 token 数量,超出的将被删除 (-1=不限制)
* @param removeFun 执行删除 token 的函数
*/
protected void addTokenIndex(SaSession session, String tokenIndexMapSaveKey, String token, long timeout, int maxTokenCount, SaParamFunction<String> removeFun) {
protected void addTokenIndex_AndAdjust(SaSession session, String tokenIndexMapSaveKey, String token, long timeout, int maxTokenCount, SaParamFunction<String> removeFun) {
Map<String, Long> tokenIndexMap = session.get(tokenIndexMapSaveKey, this::newTokenIndexMap);
if(! tokenIndexMap.containsKey(token)) {
// 添加
tokenIndexMap.put(token, ttlToExpireTime(timeout));
// 剔除过期的
tokenIndexMap = removeExpiredIndex(tokenIndexMap);
tokenIndexMap = _removeExpiredIndex(tokenIndexMap);
// 删掉溢出的
tokenIndexMap = removeOverflowIndex(tokenIndexMap, maxTokenCount, removeFun);
tokenIndexMap = _removeOverflowIndex(tokenIndexMap, maxTokenCount, removeFun);
// 保存
session.set(tokenIndexMapSaveKey, tokenIndexMap);
// 更新 TTL
long maxTtl = getMaxTtl(tokenIndexMap.values());
long maxTtl = getMaxTtlByExpireTime(tokenIndexMap.values());
if(maxTtl != 0) {
session.updateTimeout(maxTtl);
}
@@ -127,12 +133,13 @@ public class SaOAuth2Dao {
}
/**
* 在 RawSession 上删除 token 索引
* 在 RawSession 上删除 token 索引,并尝试注销 RawSession
*
* @param session 待操作的 RawSession
* @param tokenIndexMapSaveKey 在 session 上保存 token 索引列表使用的 key
* @param token 待删除的 token
*/
protected void deleteTokenIndex(SaSession session, String tokenIndexMapSaveKey, String token) {
protected void deleteTokenIndex_AndTryLogout(SaSession session, String tokenIndexMapSaveKey, String token) {
Map<String, Long> tokenIndexMap = session.get(tokenIndexMapSaveKey, this::newTokenIndexMap);
tokenIndexMap.remove(token);
// 如果删除后还有记录,就再次保存
@@ -150,8 +157,8 @@ public class SaOAuth2Dao {
* @param tokenIndexMap token 索引列表
* @return 调整后的索引列表
*/
protected Map<String, Long> removeExpiredIndex(Map<String, Long> tokenIndexMap) {
Map<String, Long> newTokenList = newTokenIndexMap();
protected Map<String, Long> _removeExpiredIndex(Map<String, Long> tokenIndexMap) {
Map<String, Long> newTokenList = newTokenIndexMap();
for (Map.Entry<String, Long> entry : tokenIndexMap.entrySet()) {
long ttl = expireTimeToTtl(entry.getValue());
if(ttl != SaTokenDao.NOT_VALUE_EXPIRE) {
@@ -169,7 +176,7 @@ public class SaOAuth2Dao {
* @param removeFun 执行删除 token 的函数
* @return 调整后的索引列表
*/
protected Map<String, Long> removeOverflowIndex(Map<String, Long> tokenIndexMap, int maxTokenCount, SaParamFunction<String> removeFun) {
protected Map<String, Long> _removeOverflowIndex(Map<String, Long> tokenIndexMap, int maxTokenCount, SaParamFunction<String> removeFun) {
// 如果当前数量未超过限制,直接返回
if (tokenIndexMap.size() <= maxTokenCount || maxTokenCount == SaTokenDao.NEVER_EXPIRE) {
@@ -203,25 +210,25 @@ public class SaOAuth2Dao {
}
/**
* 获取 Token 列表
* 从 RawSession 获取 Token 索引列表(获取之前会完整调整索引列表,保证获取的都是有效 token)
*
* @param session 待操作的 RawSession
* @param tokenIndexMapSaveKey 在 session 上保存 token 索引列表使用的 key
* @return /
*/
protected List<String> getTokenValueList(SaSession session, String tokenIndexMapSaveKey) {
protected Map<String, Long> getTokenIndexMap_FromAdjustAfter(SaSession session, String tokenIndexMapSaveKey) {
if(session == null) {
return new ArrayList<>();
return newTokenIndexMap();
}
// 根据 ttl 值过滤一遍
Map<String, Long> tokenIndexMap = session.get(tokenIndexMapSaveKey, this::newTokenIndexMap);
Map<String, Long> newTokenIndexMap = removeExpiredIndex(tokenIndexMap);
Map<String, Long> newTokenIndexMap = _removeExpiredIndex(tokenIndexMap);
// 如果调整后集合长度归零了,说明 token 已全部过期,直接注销此 RawSession
if(newTokenIndexMap.isEmpty()) {
session.logout();
return new ArrayList<>();
return newTokenIndexMap();
}
// 没有归零,但是长度变小了,说明有过期的 token,需要重写写入一遍
@@ -230,15 +237,26 @@ public class SaOAuth2Dao {
}
// 转 List 返回
return new ArrayList<>(newTokenIndexMap.keySet());
return newTokenIndexMap;
}
/**
* 从 RawSession 获取 Token 列表(获取之前会完整调整索引列表,保证获取的都是有效 token)
*
* @param session 待操作的 RawSession
* @param tokenIndexMapSaveKey 在 session 上保存 token 索引列表使用的 key
* @return /
*/
protected List<String> getTokenValueList_FromAdjustAfter(SaSession session, String tokenIndexMapSaveKey) {
return new ArrayList<>(getTokenIndexMap_FromAdjustAfter(session, tokenIndexMapSaveKey).keySet());
}
// ------------------- code 操作
/**
* 持久化Code-Model
* @param c .
* 保存CodeModel
* @param c /
*/
public void saveCode(CodeModel c) {
if(c == null) {
@@ -248,8 +266,8 @@ public class SaOAuth2Dao {
}
/**
* 删除:Code
* @param code
* 删除:CodeModel
* @param code /
*/
public void deleteCode(String code) {
if(code != null) {
@@ -258,9 +276,9 @@ public class SaOAuth2Dao {
}
/**
* 获取:Code Model
* @param code .
* @return .
* 获取:CodeModel
* @param code /
* @return /
*/
public CodeModel getCode(String code) {
if(code == null) {
@@ -273,8 +291,8 @@ public class SaOAuth2Dao {
// ------------------- code 索引
/**
* 持久化Code-索引
* @param c .
* 保存Code 索引
* @param c /
*/
public void saveCodeIndex(CodeModel c) {
if(c == null) {
@@ -284,7 +302,7 @@ public class SaOAuth2Dao {
}
/**
* 删除:Code索引
* 删除:Code 索引
* @param clientId 应用id
* @param loginId 账号id
*/
@@ -296,18 +314,18 @@ public class SaOAuth2Dao {
* 获取:Code Value
* @param clientId 应用id
* @param loginId 账号id
* @return .
* @return /
*/
public String getCodeValue(String clientId, Object loginId) {
return getSaTokenDao().get(splicingCodeIndexKey(clientId, loginId));
}
// ------------------- access_token Model
// ------------------- Access-Token Model
/**
* 持久化AccessToken-Model
* @param at .
* 保存AccessTokenModel
* @param at /
*/
public void saveAccessToken(AccessTokenModel at) {
if(at == null) {
@@ -317,7 +335,7 @@ public class SaOAuth2Dao {
}
/**
* 删除:Access-Token
* 删除:AccessTokenModel
* @param accessToken 值
*/
public void deleteAccessToken(String accessToken) {
@@ -327,9 +345,9 @@ public class SaOAuth2Dao {
}
/**
* 获取:Access-Token Model
* @param accessToken .
* @return .
* 获取:AccessTokenModel
* @param accessToken /
* @return /
*/
public AccessTokenModel getAccessToken(String accessToken) {
if(accessToken == null) {
@@ -339,20 +357,20 @@ public class SaOAuth2Dao {
}
// ------------------- access_token 索引
// ------------------- Access-Token 索引
/**
* 持久化Access-Token 索引
* 保存Access-Token 索引,并完整调整索引列表
*
* @param at /
* @param maxAccessTokenCount 允许的最多 Access-Token 数量,超出的将被删除 (-1=不限制)
*/
public void saveAccessTokenIndex(AccessTokenModel at, int maxAccessTokenCount) {
public void saveAccessTokenIndex_AndAdjust(AccessTokenModel at, int maxAccessTokenCount) {
if(at == null) {
return;
}
SaSession session = getRawSessionByAccessToken(at.clientId, at.loginId, true);
addTokenIndex(session, ACCESS_TOKEN_MAP, at.accessToken, at.getExpiresIn(), maxAccessTokenCount, this::deleteAccessToken);
addTokenIndex_AndAdjust(session, ACCESS_TOKEN_MAP, at.accessToken, at.getExpiresIn(), maxAccessTokenCount, this::deleteAccessToken);
}
/**
@@ -362,12 +380,12 @@ public class SaOAuth2Dao {
* @param loginId 账号id
* @param accessToken 值
*/
public void deleteAccessTokenIndexBySingleData(String clientId, Object loginId, String accessToken) {
public void deleteAccessTokenIndex_BySingleData(String clientId, Object loginId, String accessToken) {
SaSession session = getRawSessionByAccessToken(clientId, loginId, false);
if(session == null) {
return;
}
deleteTokenIndex(session, ACCESS_TOKEN_MAP, accessToken);
deleteTokenIndex_AndTryLogout(session, ACCESS_TOKEN_MAP, accessToken);
}
/**
@@ -380,22 +398,34 @@ public class SaOAuth2Dao {
}
/**
* 获取 Access-Token 列表:此应用下 对 某个用户 签发的所有 Access-token
* 获取 Access-Token 索引列表(获取之前会完整调整索引列表,保证获取的都是有效 AccessToken 索引)
*
* @param clientId 应用id
* @param loginId 账号id
* @return /
*/
public List<String> getAccessTokenValueList(String clientId, Object loginId) {
public Map<String, Long> getAccessTokenIndexMap_FromAdjustAfter(String clientId, Object loginId) {
SaSession session = getRawSessionByAccessToken(clientId, loginId, false);
return getTokenValueList(session, ACCESS_TOKEN_MAP);
return getTokenIndexMap_FromAdjustAfter(session, ACCESS_TOKEN_MAP);
}
/**
* 获取 Access-Token 列表(获取之前会完整调整索引列表,保证获取的都是有效 AccessToken
*
* @param clientId 应用id
* @param loginId 账号id
* @return /
*/
public List<String> getAccessTokenValueList_FromAdjustAfter(String clientId, Object loginId) {
SaSession session = getRawSessionByAccessToken(clientId, loginId, false);
return getTokenValueList_FromAdjustAfter(session, ACCESS_TOKEN_MAP);
}
// ------------------- refresh_token Model
// ------------------- Refresh-Token Model
/**
* 持久化RefreshToken-Model
* 保存RefreshTokenModel
* @param rt .
*/
public void saveRefreshToken(RefreshTokenModel rt) {
@@ -406,7 +436,7 @@ public class SaOAuth2Dao {
}
/**
* 删除:Refresh-Token
* 删除:RefreshTokenModel
* @param refreshToken 值
*/
public void deleteRefreshToken(String refreshToken) {
@@ -416,9 +446,9 @@ public class SaOAuth2Dao {
}
/**
* 获取:Refresh-Token Model
* @param refreshToken .
* @return .
* 获取:RefreshTokenModel
* @param refreshToken /
* @return /
*/
public RefreshTokenModel getRefreshToken(String refreshToken) {
if(refreshToken == null) {
@@ -428,20 +458,20 @@ public class SaOAuth2Dao {
}
// ------------------- refresh_token 索引
// ------------------- Refresh-Token 索引
/**
* 持久化Refresh-Token 索引
* 保存Refresh-Token 索引
*
* @param rt /
* @param maxRefreshTokenCount 允许的最多 Refresh-Token 数量,超出的将被删除 (-1=不限制)
*/
public void saveRefreshTokenIndex(RefreshTokenModel rt, int maxRefreshTokenCount) {
public void saveRefreshTokenIndex_AndAdjust(RefreshTokenModel rt, int maxRefreshTokenCount) {
if(rt == null) {
return;
}
SaSession session = getRawSessionByRefreshToken(rt.clientId, rt.loginId, true);
addTokenIndex(session, REFRESH_TOKEN_MAP, rt.refreshToken, rt.getExpiresIn(), maxRefreshTokenCount, this::deleteRefreshToken);
addTokenIndex_AndAdjust(session, REFRESH_TOKEN_MAP, rt.refreshToken, rt.getExpiresIn(), maxRefreshTokenCount, this::deleteRefreshToken);
}
/**
@@ -451,12 +481,12 @@ public class SaOAuth2Dao {
* @param loginId 账号id
* @param refreshToken 值
*/
public void deleteRefreshTokenIndexBySingleData(String clientId, Object loginId, String refreshToken) {
public void deleteRefreshTokenIndex_BySingleData(String clientId, Object loginId, String refreshToken) {
SaSession session = getRawSessionByRefreshToken(clientId, loginId, false);
if(session == null) {
return;
}
deleteTokenIndex(session, REFRESH_TOKEN_MAP, refreshToken);
deleteTokenIndex_AndTryLogout(session, REFRESH_TOKEN_MAP, refreshToken);
}
/**
@@ -469,22 +499,34 @@ public class SaOAuth2Dao {
}
/**
* 获取 Refresh-Token 列表:此应用下 对 某个用户 签发的所有 Refresh-token
* 获取 Refresh-Token 索引列表(获取之前会完整调整索引列表,保证获取的都是有效 RefreshToken 索引)
*
* @param clientId 应用id
* @param loginId 账号id
* @return /
*/
public List<String> getRefreshTokenValueList(String clientId, Object loginId) {
public Map<String, Long> getRefreshTokenIndexMap_FromAdjustAfter(String clientId, Object loginId) {
SaSession session = getRawSessionByRefreshToken(clientId, loginId, false);
return getTokenValueList(session, REFRESH_TOKEN_MAP);
return getTokenIndexMap_FromAdjustAfter(session, REFRESH_TOKEN_MAP);
}
/**
* 获取 Refresh-Token 列表(获取之前会完整调整索引列表,保证获取的都是有效 RefreshToken
*
* @param clientId 应用id
* @param loginId 账号id
* @return /
*/
public List<String> getRefreshTokenValueList_FromAdjustAfter(String clientId, Object loginId) {
SaSession session = getRawSessionByRefreshToken(clientId, loginId, false);
return getTokenValueList_FromAdjustAfter(session, REFRESH_TOKEN_MAP);
}
// ------------------- client_token Model
// ------------------- Client-Token Model
/**
* 持久化ClientToken-Model
* 保存ClientTokenModel
* @param ct .
*/
public void saveClientToken(ClientTokenModel ct) {
@@ -495,7 +537,7 @@ public class SaOAuth2Dao {
}
/**
* 删除:Client-Token
* 删除:ClientTokenModel
* @param clientToken 值
*/
public void deleteClientToken(String clientToken) {
@@ -505,9 +547,9 @@ public class SaOAuth2Dao {
}
/**
* 获取:Client-Token Model
* @param clientToken .
* @return .
* 获取:ClientTokenModel
* @param clientToken /
* @return /
*/
public ClientTokenModel getClientToken(String clientToken) {
if(clientToken == null) {
@@ -517,20 +559,20 @@ public class SaOAuth2Dao {
}
// ------------------- client_token 索引
// ------------------- Client-Token 索引
/**
* 持久化Client-Token 索引
* 保存Client-Token 索引
*
* @param ct /
* @param maxClientTokenCount 允许的最多 Client-Token 数量,超出的将被删除 (-1=不限制)
*/
public void saveClientTokenIndex(ClientTokenModel ct, int maxClientTokenCount) {
public void saveClientTokenIndex_AndAdjust(ClientTokenModel ct, int maxClientTokenCount) {
if(ct == null) {
return;
}
SaSession session = getRawSessionByClientToken(ct.clientId, true);
addTokenIndex(session, CLIENT_TOKEN_MAP, ct.clientToken, ct.getExpiresIn(), maxClientTokenCount, this::deleteClientToken);
addTokenIndex_AndAdjust(session, CLIENT_TOKEN_MAP, ct.clientToken, ct.getExpiresIn(), maxClientTokenCount, this::deleteClientToken);
}
/**
@@ -538,12 +580,12 @@ public class SaOAuth2Dao {
* @param clientId 应用 id
* @param clientToken 值
*/
public void deleteClientTokenIndexBySingleData(String clientId, String clientToken) {
public void deleteClientTokenIndex_BySingleData(String clientId, String clientToken) {
SaSession session = getRawSessionByClientToken(clientId, false);
if(session == null) {
return;
}
deleteTokenIndex(session, CLIENT_TOKEN_MAP, clientToken);
deleteTokenIndex_AndTryLogout(session, CLIENT_TOKEN_MAP, clientToken);
}
/**
@@ -556,21 +598,33 @@ public class SaOAuth2Dao {
}
/**
* 获取 Client-Token 列表:此应用下 对 某个用户 签发的所有 Client-token
* 获取 Client-Token 索引列表(获取之前会完整调整索引列表,保证获取的都是有效 ClientToken 索引)
*
* @param clientId 应用id
* @param loginId 账号id
* @return /
*/
public Map<String, Long> getClientTokenIndexMap_FromAdjustAfter(String clientId, Object loginId) {
SaSession session = getRawSessionByClientToken(clientId, false);
return getTokenIndexMap_FromAdjustAfter(session, CLIENT_TOKEN_MAP);
}
/**
* 获取 Client-Token 列表(获取之前会完整调整索引列表,保证获取的都是有效 ClientToken
*
* @param clientId 应用id
* @return /
*/
public List<String> getClientTokenValueList(String clientId) {
public List<String> getClientTokenValueList_FromAdjustAfter(String clientId) {
SaSession session = getRawSessionByClientToken(clientId, false);
return getTokenValueList(session, CLIENT_TOKEN_MAP);
return getTokenValueList_FromAdjustAfter(session, CLIENT_TOKEN_MAP);
}
// ------------------- GrantScope
/**
* 持久化:用户授权记录
* 保存:用户授权记录
* @param clientId 应用id
* @param loginId 账号id
* @param scopes 权限列表
@@ -607,7 +661,7 @@ public class SaOAuth2Dao {
// ------------------- State
/**
* 持久化state
* 保存state
* @param state /
*/
public void saveState(String state) {
@@ -641,8 +695,8 @@ public class SaOAuth2Dao {
// ------------------- 其它
/**
* 持久化nonce-索引
* @param c .
* 保存nonce-索引
* @param c /
*/
public void saveCodeNonceIndex(CodeModel c) {
if(c == null || SaFoxUtil.isEmpty(c.nonce)) {
@@ -667,7 +721,7 @@ public class SaOAuth2Dao {
// ------------------- 拼接key
/**
* 拼接keyCode持久化
* 拼接 keyCode 保存
* @param code 授权码
* @return key
*/
@@ -676,7 +730,7 @@ public class SaOAuth2Dao {
}
/**
* 拼接keyCode 索引
* 拼接 keyCode 索引
* @param clientId 应用id
* @param loginId 账号id
* @return key
@@ -686,7 +740,7 @@ public class SaOAuth2Dao {
}
/**
* 拼接keyAccess-Token持久化
* 拼接 keyAccess-Token 保存
* @param accessToken accessToken
* @return key
*/
@@ -695,7 +749,7 @@ public class SaOAuth2Dao {
}
/**
* 拼接keyAccess-Token RSD Value
* 拼接 keyAccess-Token RSD Value
* @param clientId 应用id
* @param loginId 账号id
* @return key
@@ -705,7 +759,16 @@ public class SaOAuth2Dao {
}
/**
* 拼接keyRefresh-Token RSD Value
* 拼接 keyRefresh-Token 保存
* @param refreshToken refreshToken
* @return key
*/
public String splicingRefreshTokenSaveKey(String refreshToken) {
return getSaTokenConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken;
}
/**
* 拼接 keyRefresh-Token RSD Value
* @param clientId 应用id
* @param loginId 账号id
* @return key
@@ -715,25 +778,7 @@ public class SaOAuth2Dao {
}
/**
* 拼接keyClient-Token RSD Value
* @param clientId 应用id
* @return key
*/
public String splicingClientTokenRSDValue(String clientId) {
return "client-token:" + clientId;
}
/**
* 拼接keyRefresh-Token持久化
* @param refreshToken refreshToken
* @return key
*/
public String splicingRefreshTokenSaveKey(String refreshToken) {
return getSaTokenConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken;
}
/**
* 拼接keyClient-Token持久化
* 拼接 keyClient-Token 保存
* @param clientToken clientToken
* @return key
*/
@@ -742,7 +787,16 @@ public class SaOAuth2Dao {
}
/**
* 拼接key用户授权记录
* 拼接 keyClient-Token RSD Value
* @param clientId 应用id
* @return key
*/
public String splicingClientTokenRSDValue(String clientId) {
return "client-token:" + clientId;
}
/**
* 拼接 key:用户授权记录
* @param clientId 应用id
* @param loginId 账号id
* @return key
@@ -752,7 +806,7 @@ public class SaOAuth2Dao {
}
/**
* 拼接keystate 参数持久化
* 拼接 keystate 参数保存
* @param state /
* @return key
*/
@@ -761,7 +815,7 @@ public class SaOAuth2Dao {
}
/**
* 拼接keycode-nonce 索引 参数持久化
* 拼接 keycode-nonce 索引 参数保存
* @param code 授权码
* @return key
*/
@@ -770,73 +824,6 @@ public class SaOAuth2Dao {
}
// -------- 工具方法
/**
* 获取一个新的 TokenMap 集合
* @return /
*/
protected Map<String, Long> newTokenIndexMap() {
return new LinkedHashMap<>();
}
/**
* 过期时间转 ttl (秒) 获取最大 ttl 值
* @param expireTimeList /
* @return /
*/
protected long getMaxTtl(Collection<Long> expireTimeList) {
long maxTtl = 0;
for (long expireTime : expireTimeList) {
long ttl = expireTimeToTtl(expireTime);
if(ttl == SaTokenDao.NEVER_EXPIRE) {
maxTtl = SaTokenDao.NEVER_EXPIRE;
break;
}
if(ttl > maxTtl) {
maxTtl = ttl;
}
}
return maxTtl;
}
/**
* 过期时间转 ttl (秒)
* @param expireTime /
* @return /
*/
protected long expireTimeToTtl(long expireTime) {
if(expireTime == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
if(expireTime == SaTokenDao.NOT_VALUE_EXPIRE) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
// TODO temp-token 模块与 apikey 模块是否也应该修改为这个逻辑 ?
long currentTime = System.currentTimeMillis();
if(expireTime < currentTime) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
return (expireTime - currentTime) / 1000;
}
/**
* ttl (秒) 转 过期时间
* @param ttl /
* @return /
*/
protected long ttlToExpireTime(long ttl) {
if(ttl == SaTokenDao.NEVER_EXPIRE) {
return SaTokenDao.NEVER_EXPIRE;
}
if(ttl == SaTokenDao.NOT_VALUE_EXPIRE) {
return SaTokenDao.NOT_VALUE_EXPIRE;
}
return ttl * 1000 + System.currentTimeMillis();
}
// -------- bean 对象代理
/**
@@ -16,8 +16,11 @@
package cn.dev33.satoken.oauth2.data.convert;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.data.model.CodeModel;
import cn.dev33.satoken.oauth2.data.model.RefreshTokenModel;
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel;
import java.util.List;
@@ -51,31 +54,58 @@ public interface SaOAuth2DataConverter {
List<String> convertRedirectUriStringToList(String redirectUris);
/**
* 将 Code 转换为 Access-Token
* 根据 RequestAuthModel 构建一个 CodeModel
* @param ra RequestAuthModel
* @return CodeModel 对象
*/
CodeModel convertRequestAuthToCode(RequestAuthModel ra);
/**
* 根据 RequestAuthModel 构建一个 AccessTokenModel
* @param ra RequestAuthModel
* @param accessTokenTimeout Access-Token 有效期 (单位:秒)
* @return AccessTokenModel 对象
*/
AccessTokenModel convertRequestAuthToAccessToken(RequestAuthModel ra, long accessTokenTimeout);
/**
* 根据 Code 构建一个 Access-Token
* @param cm CodeModel对象
* @param accessTokenTimeout Access-Token 有效期 (单位:秒)
* @return AccessToken对象
*/
AccessTokenModel convertCodeToAccessToken(CodeModel cm);
AccessTokenModel convertCodeToAccessToken(CodeModel cm, long accessTokenTimeout);
/**
* Access-Token 转换为 Refresh-Token
* 根据 Access-Token 构建一个 Refresh-Token
* @param at /
* @param refreshTokenTimeout Refresh-Token 有效期 (单位:秒)
* @return /
*/
RefreshTokenModel convertAccessTokenToRefreshToken(AccessTokenModel at);
RefreshTokenModel convertAccessTokenToRefreshToken(AccessTokenModel at, long refreshTokenTimeout);
/**
* Refresh-Token 转换为 Access-Token
* 根据 Refresh-Token 构建一个 Access-Token
* @param rt /
* @param accessTokenTimeout Access-Token 有效期 (单位:秒)
* @return /
*/
AccessTokenModel convertRefreshTokenToAccessToken(RefreshTokenModel rt);
AccessTokenModel convertRefreshTokenToAccessToken(RefreshTokenModel rt, long accessTokenTimeout);
/**
* 根据 Refresh-Token 建一个新的 Refresh-Token
* 根据 Refresh-Token 建一个新的 Refresh-Token
* @param rt /
* @param refreshTokenTimeout Refresh-Token 有效期 (单位:秒)
* @return /
*/
RefreshTokenModel convertRefreshTokenToRefreshToken(RefreshTokenModel rt);
RefreshTokenModel convertRefreshTokenToRefreshToken(RefreshTokenModel rt, long refreshTokenTimeout);
/**
* 根据 SaClientModel 构建一个 ClientTokenModel
* @param clientModel /
* @param scopes 权限列表
* @return /
*/
ClientTokenModel convertSaClientToClientToken(SaClientModel clientModel, List<String> scopes);
}
@@ -15,15 +15,17 @@
*/
package cn.dev33.satoken.oauth2.data.convert;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.consts.GrantType;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.data.model.CodeModel;
import cn.dev33.satoken.oauth2.data.model.RefreshTokenModel;
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
import cn.dev33.satoken.oauth2.data.model.request.RequestAuthModel;
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
import cn.dev33.satoken.util.SaFoxUtil;
import cn.dev33.satoken.util.SaTtlMethods;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -35,7 +37,7 @@ import java.util.List;
* @author click33
* @since 1.39.0
*/
public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter, SaTtlMethods {
/**
* 转换 scope 数据格式:String -> List
@@ -72,10 +74,47 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
}
/**
* 将 Code 转换为 Access-Token
* 根据 RequestAuthModel 构建一个 CodeModel
* @param ra RequestAuthModel
* @return CodeModel 对象
*/
@Override
public AccessTokenModel convertCodeToAccessToken(CodeModel cm) {
public CodeModel convertRequestAuthToCode(RequestAuthModel ra){
String codeValue = SaOAuth2Strategy.instance.createCodeValue.execute(ra.clientId, ra.loginId, ra.scopes);
CodeModel cm = new CodeModel();
cm.code = codeValue;
cm.clientId = ra.clientId;
cm.scopes = ra.scopes;
cm.loginId = ra.loginId;
cm.redirectUri = ra.redirectUri;
cm.nonce = ra.getNonce();
return cm;
}
/**
* 根据 RequestAuthModel 构建一个 AccessTokenModel
* @param ra RequestAuthModel
* @return AccessTokenModel 对象
*/
@Override
public AccessTokenModel convertRequestAuthToAccessToken(RequestAuthModel ra, long accessTokenTimeout) {
String newAtValue = SaOAuth2Strategy.instance.createAccessToken.execute(ra.clientId, ra.loginId, ra.scopes);
AccessTokenModel at = new AccessTokenModel();
at.accessToken = newAtValue;
at.clientId = ra.clientId;
at.loginId = ra.loginId;
at.scopes = ra.scopes;
at.tokenType = SaOAuth2Consts.TokenType.bearer;
at.expiresTime = ttlToExpireTime(accessTokenTimeout);
at.extraData = new LinkedHashMap<>();
return at;
}
/**
* 根据 Code 构建一个 Access-Token
*/
@Override
public AccessTokenModel convertCodeToAccessToken(CodeModel cm, long accessTokenTimeout) {
AccessTokenModel at = new AccessTokenModel();
at.accessToken = SaOAuth2Strategy.instance.createAccessToken.execute(cm.clientId, cm.loginId, cm.scopes);
at.clientId = cm.clientId;
@@ -83,40 +122,31 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
at.scopes = cm.scopes;
at.tokenType = SaOAuth2Consts.TokenType.bearer;
at.grantType = GrantType.authorization_code;
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(cm.clientId);
at.expiresTime = System.currentTimeMillis() + (clientModel.getAccessTokenTimeout() * 1000);
at.expiresTime = ttlToExpireTime(accessTokenTimeout);
at.extraData = new LinkedHashMap<>();
return at;
}
/**
* Access-Token 转换为 Refresh-Token
* @param at .
* @return .
* 根据 Access-Token 构建一个 Refresh-Token
*/
@Override
public RefreshTokenModel convertAccessTokenToRefreshToken(AccessTokenModel at) {
public RefreshTokenModel convertAccessTokenToRefreshToken(AccessTokenModel at, long refreshTokenTimeout) {
RefreshTokenModel rt = new RefreshTokenModel();
rt.refreshToken = SaOAuth2Strategy.instance.createRefreshToken.execute(at.clientId, at.loginId, at.scopes);
rt.clientId = at.clientId;
rt.loginId = at.loginId;
rt.scopes = at.scopes;
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(at.clientId);
rt.expiresTime = System.currentTimeMillis() + (clientModel.getRefreshTokenTimeout() * 1000);
rt.expiresTime = ttlToExpireTime(refreshTokenTimeout);
rt.extraData = new LinkedHashMap<>(at.extraData);
// 改变 at 属性
// at.refreshToken = rt.refreshToken;
// at.refreshExpiresTime = rt.expiresTime;
return rt;
}
/**
* Refresh-Token 转换为 Access-Token
* @param rt .
* @return .
* 根据 Refresh-Token 构建一个 Access-Token
*/
@Override
public AccessTokenModel convertRefreshTokenToAccessToken(RefreshTokenModel rt) {
public AccessTokenModel convertRefreshTokenToAccessToken(RefreshTokenModel rt, long accessTokenTimeout) {
AccessTokenModel at = new AccessTokenModel();
at.accessToken = SaOAuth2Strategy.instance.createAccessToken.execute(rt.clientId, rt.loginId, rt.scopes);
at.refreshToken = rt.refreshToken;
@@ -126,23 +156,19 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
at.tokenType = SaOAuth2Consts.TokenType.bearer;
at.grantType = GrantType.refresh_token;
at.extraData = new LinkedHashMap<>(rt.extraData);
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(rt.clientId);
at.expiresTime = System.currentTimeMillis() + (clientModel.getAccessTokenTimeout() * 1000);
at.expiresTime = ttlToExpireTime(accessTokenTimeout);
at.refreshExpiresTime = rt.expiresTime;
return at;
}
/**
* 根据 Refresh-Token 建一个新的 Refresh-Token
* @param rt .
* @return .
* 根据 Refresh-Token 建一个新的 Refresh-Token
*/
@Override
public RefreshTokenModel convertRefreshTokenToRefreshToken(RefreshTokenModel rt) {
public RefreshTokenModel convertRefreshTokenToRefreshToken(RefreshTokenModel rt, long refreshTokenTimeout) {
RefreshTokenModel newRt = new RefreshTokenModel();
newRt.refreshToken = SaOAuth2Strategy.instance.createRefreshToken.execute(rt.clientId, rt.loginId, rt.scopes);
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(rt.clientId);
newRt.expiresTime = System.currentTimeMillis() + (clientModel.getRefreshTokenTimeout() * 1000);
newRt.expiresTime = ttlToExpireTime(refreshTokenTimeout);
newRt.clientId = rt.clientId;
newRt.scopes = rt.scopes;
newRt.loginId = rt.loginId;
@@ -150,5 +176,25 @@ public class SaOAuth2DataConverterDefaultImpl implements SaOAuth2DataConverter {
return newRt;
}
/**
* 根据 SaClientModel 构建一个 ClientTokenModel
* @param clientModel /
* @param scopes 权限列表
* @return /
*/
@Override
public ClientTokenModel convertSaClientToClientToken(SaClientModel clientModel, List<String> scopes) {
String clientTokenValue = SaOAuth2Strategy.instance.createClientToken.execute(clientModel.getClientId(), scopes);
ClientTokenModel ct = new ClientTokenModel(clientTokenValue, clientModel.getClientId(), scopes);
ct.clientToken = clientTokenValue;
ct.clientId = clientModel.getClientId();
ct.scopes = scopes;
ct.tokenType = SaOAuth2Consts.TokenType.bearer;
ct.expiresTime = ttlToExpireTime(clientModel.getClientTokenTimeout());
ct.grantType = GrantType.client_credentials;
ct.extraData = new LinkedHashMap<>();
return ct;
}
}
@@ -32,28 +32,28 @@ import java.util.function.Consumer;
public interface SaOAuth2DataGenerate {
/**
* 构建ModelCode授权码
* 构建 ModelCode授权码
* @param ra 请求参数Model
* @return 授权码Model
*/
CodeModel generateCode(RequestAuthModel ra);
/**
* 构建ModelAccess-Token (根据 code 授权码)
* 构建 ModelAccess-Token (根据 code 授权码)
* @param code 授权码Model
* @return AccessToken Model
*/
AccessTokenModel generateAccessToken(String code);
/**
* 刷新Model:根据 Refresh-Token 生成一个新的 Access-Token
* 刷新 Model:根据 Refresh-Token 生成一个新的 Access-Token
* @param refreshToken Refresh-Token值
* @return 新的 Access-Token
*/
AccessTokenModel refreshAccessToken(String refreshToken);
/**
* 构建ModelAccess-Token (根据RequestAuthModel构建,用于隐藏式 and 密码式)
* 构建 ModelAccess-Token (根据 RequestAuthModel 构建,用于隐藏式 and 密码式)
* @param ra 请求参数Model
* @param isCreateRt 是否生成对应的Refresh-Token
* @param appendWork 对生成的 AccessTokenModel 进行追加操作
@@ -62,7 +62,7 @@ public interface SaOAuth2DataGenerate {
AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt, Consumer<AccessTokenModel> appendWork);
/**
* 构建ModelClient-Token
* 构建 ModelClient-Token
* @param clientId 应用id
* @param scopes 授权范围
* @return Client-Token Model
@@ -70,7 +70,7 @@ public interface SaOAuth2DataGenerate {
ClientTokenModel generateClientToken(String clientId, List<String> scopes);
/**
* 构建URL:下放Code URL (Authorization Code 授权码)
* 构建 URL:下放Code URL (Authorization Code 授权码)
* @param redirectUri 下放地址
* @param code code参数
* @param state state参数
@@ -79,7 +79,7 @@ public interface SaOAuth2DataGenerate {
String buildRedirectUri(String redirectUri, String code, String state);
/**
* 构建URL:下放Access-Token URL implicit 隐藏式)
* 构建 URL:下放Access-Token URL implicit 隐藏式)
* @param redirectUri 下放地址
* @param token token
* @param state state参数
@@ -16,7 +16,6 @@
package cn.dev33.satoken.oauth2.data.generate;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.consts.GrantType;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.dao.SaOAuth2Dao;
import cn.dev33.satoken.oauth2.data.convert.SaOAuth2DataConverter;
@@ -32,8 +31,8 @@ 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.SaTtlMethods;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.function.Consumer;
@@ -43,10 +42,10 @@ import java.util.function.Consumer;
* @author click33
* @since 1.39.0
*/
public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate, SaTtlMethods {
/**
* 构建ModelCode授权码
* 构建 ModelCode授权码
* @param ra 请求参数Model
* @return 授权码Model
*/
@@ -55,18 +54,17 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
// 删除旧Code
// 删除旧 Code
dao.deleteCode(dao.getCodeValue(ra.clientId, ra.loginId));
// 生成新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, ra.getNonce());
// 生成新 Code
CodeModel cm = SaOAuth2Manager.getDataConverter().convertRequestAuthToCode(ra);
// 保存新Code
// 保存新 Code
dao.saveCode(cm);
dao.saveCodeIndex(cm);
// 保存code-nonce
// 保存 code -> nonce
dao.saveCodeNonceIndex(cm);
// 返回
@@ -74,7 +72,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
}
/**
* 构建ModelAccess-Token (根据 code 授权码)
* 构建 ModelAccess-Token (根据 code 授权码)
* @param code 授权码
* @return AccessToken Model
*/
@@ -91,30 +89,32 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
// 2、开发者自定义的授权前置检查
SaOAuth2Strategy.instance.userAuthorizeClientCheck.run(cm.loginId, cm.clientId);
// 3、生成token
AccessTokenModel at = dataConverter.convertCodeToAccessToken(cm);
// 3、生成新 Access-Token
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(cm.clientId);
AccessTokenModel at = dataConverter.convertCodeToAccessToken(cm, clientModel.getAccessTokenTimeout());
SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);
RefreshTokenModel rt = dataConverter.convertAccessTokenToRefreshToken(at);
// 4、生成新 Refresh-Token
RefreshTokenModel rt = dataConverter.convertAccessTokenToRefreshToken(at, clientModel.getRefreshTokenTimeout());
at.refreshToken = rt.refreshToken;
at.refreshExpiresTime = rt.expiresTime;
// 4、保存token
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(cm.clientId);
// 5、保存 Access-Token、Refresh-Token
dao.saveAccessToken(at);
dao.saveAccessTokenIndex(at, clientModel.getMaxAccessTokenCount());
dao.saveAccessTokenIndex_AndAdjust(at, clientModel.getMaxAccessTokenCount());
dao.saveRefreshToken(rt);
dao.saveRefreshTokenIndex(rt, clientModel.getMaxRefreshTokenCount());
dao.saveRefreshTokenIndex_AndAdjust(rt, clientModel.getMaxRefreshTokenCount());
// 5、删除Code
// 6、删除 Code (一个 code 只可以使用一次)
dao.deleteCode(code);
dao.deleteCodeIndex(cm.clientId, cm.loginId);
// 6、返回 Access-Token
// 7、返回 Access-Token
return at;
}
/**
* 刷新Model:根据 Refresh-Token 生成一个新的 Access-Token
* 刷新 Model:根据 Refresh-Token 生成一个新的 Access-Token
* @param refreshToken Refresh-Token值
* @return 新的 Access-Token
*/
@@ -123,42 +123,35 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
// 获取 Refresh-Token 信息
// 1、获取 Refresh-Token 信息
RefreshTokenModel rt = dao.getRefreshToken(refreshToken);
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效 refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30111);
// 开发者自定义的授权前置检查
// 2、开发者自定义的授权前置检查
SaOAuth2Strategy.instance.userAuthorizeClientCheck.run(rt.loginId, rt.clientId);
// 如果配置了 [每次刷新产生新的Refresh-Token]
// 3、如果配置了 isNewRefresh=true,则生成一个新的 Refresh-Token
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(rt.clientId);
if(clientModel.getIsNewRefresh()) {
// 删除旧 Refresh-Token
// dao.deleteRefreshToken(rt.refreshToken);
// 创建并保存新的 Refresh-Token
rt = SaOAuth2Manager.getDataConverter().convertRefreshTokenToRefreshToken(rt);
rt = SaOAuth2Manager.getDataConverter().convertRefreshTokenToRefreshToken(rt, clientModel.getRefreshTokenTimeout());
dao.saveRefreshToken(rt);
dao.saveRefreshTokenIndex(rt, clientModel.getMaxRefreshTokenCount());
dao.saveRefreshTokenIndex_AndAdjust(rt, clientModel.getMaxRefreshTokenCount());
}
// 删除旧 Access-Token
// dao.deleteAccessToken(dao.getAccessTokenList(rt.clientId, rt.loginId));
// 生成新 Access-Token
AccessTokenModel at = SaOAuth2Manager.getDataConverter().convertRefreshTokenToAccessToken(rt);
// 4、生成新 Access-Token
AccessTokenModel at = SaOAuth2Manager.getDataConverter().convertRefreshTokenToAccessToken(rt, clientModel.getAccessTokenTimeout());
SaOAuth2Strategy.instance.refreshAccessTokenWorkByScope.accept(at);
// 保存新 Access-Token
// 5、保存新 Access-Token
dao.saveAccessToken(at);
dao.saveAccessTokenIndex(at, clientModel.getMaxAccessTokenCount());
dao.saveAccessTokenIndex_AndAdjust(at, clientModel.getMaxAccessTokenCount());
// 返回新 Access-Token
// 6、返回新 Access-Token
return at;
}
/**
* 构建ModelAccess-Token (根据RequestAuthModel构建,用于隐藏式 and 密码式)
* 构建 ModelAccess-Token (根据 RequestAuthModel 构建,用于隐藏式 and 密码式)
* @param ra 请求参数Model
* @param isCreateRt 是否生成对应的Refresh-Token
* @param appendWork 对生成的 AccessTokenModel 进行追加操作
@@ -169,51 +162,39 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
public AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt, Consumer<AccessTokenModel> appendWork) {
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
// 1、删除 旧Token
// dao.deleteAccessToken(dao.getAccessTokenList(ra.clientId, ra.loginId));
// if(isCreateRt) {
// dao.deleteRefreshToken(dao.getRefreshTokenValue(ra.clientId, ra.loginId));
// }
SaOAuth2DataConverter dataConverter = SaOAuth2Manager.getDataConverter();
// 1、开发者自定义的授权前置检查
SaOAuth2Strategy.instance.userAuthorizeClientCheck.run(ra.loginId, ra.clientId);
// 2、生成 Access-Token
String newAtValue = SaOAuth2Strategy.instance.createAccessToken.execute(ra.clientId, ra.loginId, ra.scopes);
AccessTokenModel at = new AccessTokenModel(newAtValue, ra.clientId, ra.loginId, ra.scopes);
at.tokenType = SaOAuth2Consts.TokenType.bearer;
// 2、生成 Access-Token
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(ra.clientId);
AccessTokenModel at = dataConverter.convertRequestAuthToAccessToken(ra, clientModel.getAccessTokenTimeout());
if(appendWork != null) {
appendWork.accept(at);
}
// 3、根据权限构建额外参数
at.extraData = new LinkedHashMap<>();
SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(ra.clientId);
at.expiresTime = System.currentTimeMillis() + (clientModel.getAccessTokenTimeout() * 1000);
// 3、生成&保存 Refresh-Token
// 3、生成 & 保存 Refresh-Token
if(isCreateRt) {
RefreshTokenModel rt = SaOAuth2Manager.getDataConverter().convertAccessTokenToRefreshToken(at);
RefreshTokenModel rt = dataConverter.convertAccessTokenToRefreshToken(at, clientModel.getRefreshTokenTimeout());
at.refreshToken = rt.refreshToken;
at.refreshExpiresTime = rt.expiresTime;
dao.saveRefreshToken(rt);
dao.saveRefreshTokenIndex(rt, clientModel.getMaxRefreshTokenCount());
dao.saveRefreshTokenIndex_AndAdjust(rt, clientModel.getMaxRefreshTokenCount());
}
// 5、保存 Access-Token
// 4、保存 Access-Token
dao.saveAccessToken(at);
dao.saveAccessTokenIndex(at, clientModel.getMaxAccessTokenCount());
dao.saveAccessTokenIndex_AndAdjust(at, clientModel.getMaxAccessTokenCount());
// 6、返回 Access-Token
// 5、返回 Access-Token
return at;
}
/**
* 构建ModelClient-Token
* 构建 ModelClient-Token
* @param clientId 应用id
* @param scopes 授权范围
* @return Client-Token Model
@@ -223,39 +204,23 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
// 1、删掉旧 Lower-Client-Token
// dao.deleteClientToken(dao.getLowerClientTokenValue(clientId));
// 1、如果配置了 Lower-Client-Token 的 ttl ,则需要更新一下
SaClientModel clientModel = SaOAuth2Manager.getDataLoader().getClientModelNotNull(clientId);
// 2、将旧Client-Token 标记为新 Lower-Client-Token
// ClientTokenModel oldCt = dao.getClientToken(dao.getClientTokenValue(clientId));
// dao.saveLowerClientTokenIndex(oldCt);
// 2.5、如果配置了 Lower-Client-Token 的 ttl ,则需要更新一下
SaClientModel cm = SaOAuth2Manager.getDataLoader().getClientModelNotNull(clientId);
// if(oldCt != null && cm.getLowerClientTokenTimeout() != -1) {
// oldCt.expiresTime = System.currentTimeMillis() + (cm.getLowerClientTokenTimeout() * 1000);
// dao.saveClientToken(oldCt);
// }
// 3、生成新 Client-Token
String clientTokenValue = SaOAuth2Strategy.instance.createClientToken.execute(clientId, scopes);
ClientTokenModel ct = new ClientTokenModel(clientTokenValue, clientId, scopes);
ct.tokenType = SaOAuth2Consts.TokenType.bearer;
ct.expiresTime = System.currentTimeMillis() + (cm.getClientTokenTimeout() * 1000);
ct.grantType = GrantType.client_credentials;
ct.extraData = new LinkedHashMap<>();
// 2、生成 Client-Token
ClientTokenModel ct = SaOAuth2Manager.getDataConverter().convertSaClientToClientToken(clientModel, scopes);
SaOAuth2Strategy.instance.workClientTokenByScope.accept(ct);
// 3、保存Client-Token
// 3、保存 Client-Token
dao.saveClientToken(ct);
dao.saveClientTokenIndex(ct, cm.getMaxClientTokenCount());
dao.saveClientTokenIndex_AndAdjust(ct, clientModel.getMaxClientTokenCount());
// 4、返回
return ct;
}
/**
* 构建URL:下放Code URL (Authorization Code 授权码)
* 构建 URL:下放Code URL (Authorization Code 授权码)
* @param redirectUri 下放地址
* @param code code参数
* @param state state参数
@@ -272,7 +237,7 @@ public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {
}
/**
* 构建URL:下放Access-Token URL implicit 隐藏式)
* 构建 URL:下放Access-Token URL implicit 隐藏式)
* @param redirectUri 下放地址
* @param token token
* @param state state参数
@@ -57,7 +57,7 @@ public interface SaOAuth2DataLoader {
}
/**
* 根据 ClientId 和 LoginId 获取openid
* 根据 ClientId 和 LoginId 获取 openid
*
* @param clientId 应用id
* @param loginId 账号id
@@ -104,6 +104,28 @@ public class AccessTokenModel implements Serializable {
this.scopes = scopes;
}
// 额外追加方法
/**
* 获取:此 Access-Token 的剩余有效期(秒)
* @return /
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
/**
* 获取:此 Refresh-Token 的剩余有效期(秒)
* @return /
*/
public long getRefreshExpiresIn() {
long s = (refreshExpiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
// get set
public String getAccessToken() {
return accessToken;
@@ -221,24 +243,5 @@ public class AccessTokenModel implements Serializable {
'}';
}
// 追加只读属性
/**
* 获取:此 Access-Token 的剩余有效期(秒)
* @return /
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
/**
* 获取:此 Refresh-Token 的剩余有效期(秒)
* @return /
*/
public long getRefreshExpiresIn() {
long s = (refreshExpiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
}
@@ -86,6 +86,20 @@ public class ClientTokenModel implements Serializable {
this.scopes = scopes;
}
// 额外追加方法
/**
* 获取:此 Client-Token 的剩余有效期(秒)
* @return /
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
// get set
public String getClientToken() {
return clientToken;
}
@@ -172,13 +186,4 @@ public class ClientTokenModel implements Serializable {
'}';
}
/**
* 获取:此 Client-Token 的剩余有效期(秒)
* @return /
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
}
@@ -69,13 +69,15 @@ public class CodeModel implements Serializable {
public CodeModel() {
this.createTime = System.currentTimeMillis();
}
/**
* 构建一个
* @param code 授权码
* @param clientId 应用id
* @param scopes 请求授权范围
* @param loginId 对应的账号id
* @param redirectUri 重定向地址
* @param redirectUri 重定向地址
* @param nonce 随机数
*/
public CodeModel(String code, String clientId, List<String> scopes, Object loginId, String redirectUri, String nonce) {
this();
@@ -69,6 +69,20 @@ public class RefreshTokenModel implements Serializable {
}
// 额外追加方法
/**
* 获取:此 Refresh-Token 的剩余有效期(秒)
* @return /
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
// get set
public String getRefreshToken() {
return refreshToken;
}
@@ -145,13 +159,4 @@ public class RefreshTokenModel implements Serializable {
"]";
}
/**
* 获取:此 Refresh-Token 的剩余有效期(秒)
* @return /
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
}
@@ -15,8 +15,7 @@
*/
package cn.dev33.satoken.oauth2.data.model.loader;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2ServerConfig;
import cn.dev33.satoken.oauth2.strategy.SaOAuth2Strategy;
import java.io.Serializable;
import java.util.ArrayList;
@@ -92,15 +91,7 @@ public class SaClientModel implements Serializable {
public SaClientModel() {
SaOAuth2ServerConfig config = SaOAuth2Manager.getServerConfig();
this.isNewRefresh = config.getIsNewRefresh();
this.accessTokenTimeout = config.getAccessTokenTimeout();
this.refreshTokenTimeout = config.getRefreshTokenTimeout();
this.clientTokenTimeout = config.getClientTokenTimeout();
this.lowerClientTokenTimeout = config.getLowerClientTokenTimeout();
this.maxAccessTokenCount = config.getMaxAccessTokenCount();
this.maxRefreshTokenCount = config.getMaxRefreshTokenCount();
this.maxClientTokenCount = config.getMaxClientTokenCount();
SaOAuth2Strategy.instance.setSaClientModelDefaultFields.run(this);
}
public SaClientModel(String clientId, String clientSecret, List<String> contractScopes, List<String> allowRedirectUris) {
this();
@@ -84,4 +84,5 @@ public class ClientIdAndSecretModel implements Serializable {
", clientSecret='" + clientSecret + '\'' +
'}';
}
}
@@ -15,13 +15,13 @@
*/
package cn.dev33.satoken.oauth2.data.model.request;
import java.io.Serializable;
import java.util.List;
import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode;
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
import cn.dev33.satoken.util.SaFoxUtil;
import java.io.Serializable;
import java.util.List;
/**
* 请求授权参数的 Model
*
@@ -181,7 +181,7 @@ public class RequestAuthModel implements Serializable {
}
/**
* 检查此Model参数是否有效
* 数据自
* @return 对象自身
*/
public RequestAuthModel checkModel() {
@@ -200,5 +200,17 @@ public class RequestAuthModel implements Serializable {
return this;
}
@Override
public String toString() {
return "RequestAuthModel{" +
"clientId='" + clientId + '\'' +
", scopes=" + scopes +
", loginId=" + loginId +
", redirectUri='" + redirectUri + '\'' +
", responseType='" + responseType + '\'' +
", state='" + state + '\'' +
", nonce='" + nonce + '\'' +
'}';
}
}
@@ -66,7 +66,6 @@ public interface SaOAuth2DataResolver {
*/
RequestAuthModel readRequestAuthModel(SaRequest req, Object loginId);
/**
* 构建返回值: 获取 token
* @param at token信息
@@ -77,7 +77,7 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
*/
@Override
public String readAccessToken(SaRequest request) {
// 优先从请求参数中获取
// 优先从请求参数中获取,可以读取到的话直接返回
String accessToken = request.getParam(Param.access_token);
if(SaFoxUtil.isNotEmpty(accessToken)) {
return accessToken;
@@ -104,7 +104,7 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
*/
@Override
public String readClientToken(SaRequest request) {
// 优先从请求参数中获取
// 优先从请求参数中获取,可以读取到的话直接返回
String clientToken = request.getParam(Param.client_token);
if(SaFoxUtil.isNotEmpty(clientToken)) {
return clientToken;
@@ -172,7 +172,7 @@ public class SaOAuth2DataResolverDefaultImpl implements SaOAuth2DataResolver {
Map<String, Object> map = new LinkedHashMap<>();
map.put("token_type", ct.tokenType);
map.put("client_token", ct.clientToken);
if(SaOAuth2Manager.getServerConfig().mode4ReturnAccessToken) {
if(SaOAuth2Manager.getServerConfig().getMode4ReturnAccessToken()) {
map.put("access_token", ct.clientToken);
}
map.put("expires_in", ct.getExpiresIn());
@@ -17,8 +17,8 @@ package cn.dev33.satoken.oauth2.granttype.handler;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.consts.GrantType;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.request.ClientIdAndSecretModel;
@@ -39,9 +39,7 @@ public class AuthorizationCodeGrantTypeHandler implements SaOAuth2GrantTypeHandl
@Override
public AccessTokenModel getAccessToken(SaRequest req, String clientId, List<String> scopes) {
// 获取参数
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
// String clientId = clientIdAndSecret.clientId;
String clientSecret = clientIdAndSecret.clientSecret;
String code = req.getParamNotNull(SaOAuth2Consts.Param.code);
String redirectUri = req.getParam(SaOAuth2Consts.Param.redirect_uri);
@@ -50,8 +48,7 @@ public class AuthorizationCodeGrantTypeHandler implements SaOAuth2GrantTypeHandl
SaOAuth2Manager.getTemplate().checkGainTokenParam(code, clientId, clientSecret, redirectUri);
// 构建 Access-Token、返回
AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().generateAccessToken(code);
return accessTokenModel;
return SaOAuth2Manager.getDataGenerate().generateAccessToken(code);
}
}
@@ -49,20 +49,20 @@ public class PasswordGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterfa
String username = req.getParamNotNull(SaOAuth2Consts.Param.username);
String password = req.getParamNotNull(SaOAuth2Consts.Param.password);
// 3、调用API 开始登录,如果没能成功登录,则直接退出
// 2、调用API 开始登录,如果没能成功登录,则直接退出
PasswordAuthResult passwordAuthResult = loginByUsernamePassword(username, password);
Object loginId = passwordAuthResult.getLoginId();
if(loginId == null) {
throw new SaOAuth2Exception("登录失败").setCode(SaOAuth2ErrorCode.CODE_30161);
}
// 4、构建 ra 对象
// 3、构建 ra 对象
RequestAuthModel ra = new RequestAuthModel();
ra.clientId = clientId;
ra.loginId = loginId;
ra.scopes = scopes;
// 5、生成 Access-Token
// 4、生成 Access-Token
AccessTokenModel at = SaOAuth2Manager.getDataGenerate().generateAccessToken(ra, true, atm -> atm.grantType = GrantType.password);
return at;
}
@@ -21,7 +21,7 @@ import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import java.util.List;
/**
* 所有 OAuth2 GrantType 处理器的父接口
* 所有 OAuth2 GrantType 处理器的父接口,如果要自定义 GrantType 处理器,必须实现此接口
*
* @author click33
* @since 1.39.0
@@ -182,8 +182,12 @@ public class SaOAuth2ServerProcessor {
*/
public Object refresh() {
SaRequest req = SaHolder.getRequest();
// 校验 grant_type 必须为 refresh_token
String grantType = req.getParamNotNull(Param.grant_type);
SaOAuth2Exception.throwBy(!grantType.equals(GrantType.refresh_token), "无效 grant_type" + grantType, SaOAuth2ErrorCode.CODE_30126);
// 刷新 Access-Token
AccessTokenModel accessTokenModel = SaOAuth2Strategy.instance.grantTypeAuth.apply(req);
return SaOAuth2Manager.getDataResolver().buildRefreshTokenReturnValue(accessTokenModel);
}
@@ -205,7 +209,7 @@ public class SaOAuth2ServerProcessor {
// 如果 Access-Token 不存在,直接返回
if(oauth2Template.getAccessToken(accessToken) == null) {
return SaResult.ok("access_token不存在:" + accessToken);
return SaResult.ok("access_token 不存在:" + accessToken);
}
// 校验参数
@@ -223,9 +227,7 @@ public class SaOAuth2ServerProcessor {
* @return 处理结果
*/
public Object doLogin() {
// 获取变量
SaRequest req = SaHolder.getRequest();
return SaOAuth2Strategy.instance.doLoginHandle.apply(req.getParam(Param.name), req.getParam(Param.pwd));
}
@@ -262,10 +264,10 @@ public class SaOAuth2ServerProcessor {
// -------- 情况2:需要返回最终的 redirect_uri 地址
// s3、构建请求 Model
// 构建请求 Model
RequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, loginId);
// 7、判断授权类型,构建不同的重定向地址
// 判断授权类型,构建不同的重定向地址
// 如果是 授权码式,则:开始重定向授权,下放code
if(ResponseType.code.equals(ra.responseType)) {
CodeModel codeModel = dataGenerate.generateCode(ra);
@@ -311,7 +313,7 @@ public class SaOAuth2ServerProcessor {
String clientSecret = clientIdAndSecret.clientSecret;
List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(req.getParam(Param.scope));
//校验 ClientScope
// 校验 ClientScope
oauth2Template.checkContractScope(clientId, scopes);
// 校验 ClientSecret
@@ -16,7 +16,7 @@
package cn.dev33.satoken.oauth2.scope;
/**
* OAuth2 常见权限定义
* OAuth2 常见 Scope 定义
*
* @author click33
* @since 1.39.0
@@ -120,8 +120,8 @@ public class OidcScopeHandler implements SaOAuth2ScopeHandlerInterface {
public String getNonce() {
String nonce = SaHolder.getRequest().getParam(SaOAuth2Consts.Param.nonce);
if(SaFoxUtil.isEmpty(nonce)) {
//通过code查找nonce
//为了避免其它handler可能会用到nonce,任由其自然过期,只取用不删除
// 通过 code 查找nonce
// 为了避免其它 handler 可能会用到 nonce, 任由其自然过期,只取用不删除
nonce = SaOAuth2Manager.getDao().getNonce(SaHolder.getRequest().getParam(SaOAuth2Consts.Param.code));
}
if(SaFoxUtil.isEmpty(nonce)) {
@@ -136,7 +136,7 @@ public class OidcScopeHandler implements SaOAuth2ScopeHandlerInterface {
* @return /
*/
public IdTokenModel workExtraData(IdTokenModel idToken) {
//
// 留给开发者扩展
return idToken;
}
@@ -19,7 +19,7 @@ import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
/**
* 所有 OAuth2 权限处理器的父接口
* 所有 OAuth2 权限处理器的父接口,如果要自定义 Scope 处理器,必须实现此接口
*
* @author click33
* @since 1.39.0
@@ -16,6 +16,7 @@
package cn.dev33.satoken.oauth2.strategy;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.fun.SaParamFunction;
import cn.dev33.satoken.fun.SaTwoParamFunction;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2ServerConfig;
@@ -64,12 +65,12 @@ public final class SaOAuth2Strategy {
// ------------------ 权限处理器 ------------------
/**
* 权限处理器集合
* Scope 权限处理器集合
*/
public Map<String, SaOAuth2ScopeHandlerInterface> scopeHandlerMap = new LinkedHashMap<>();
/**
* 注册所有默认的权限处理器
* 注册所有默认的 Scope 权限处理器
*/
public void registerDefaultScopeHandler() {
scopeHandlerMap.put(CommonScope.OPENID, new OpenIdScopeHandler());
@@ -156,7 +157,7 @@ public final class SaOAuth2Strategy {
public Map<String, SaOAuth2GrantTypeHandlerInterface> grantTypeHandlerMap = new LinkedHashMap<>();
/**
* 注册所有默认的权限处理器
* 注册所有默认的 grant_type 处理器
*/
public void registerDefaultGrantTypeHandler() {
grantTypeHandlerMap.put(GrantType.authorization_code, new AuthorizationCodeGrantTypeHandler());
@@ -165,7 +166,7 @@ public final class SaOAuth2Strategy {
}
/**
* 注册一个权限处理器
* 注册一个 grant_type 处理器
*/
public void registerGrantTypeHandler(SaOAuth2GrantTypeHandlerInterface handler) {
grantTypeHandlerMap.put(handler.getHandlerGrantType(), handler);
@@ -173,7 +174,7 @@ public final class SaOAuth2Strategy {
}
/**
* 移除一个权限处理器
* 移除一个 grant_type 处理器
*/
public void removeGrantTypeHandler(String scope) {
scopeHandlerMap.remove(scope);
@@ -183,13 +184,14 @@ public final class SaOAuth2Strategy {
* 根据 grantType 构造一个 AccessTokenModel
*/
public SaOAuth2GrantTypeAuthFunction grantTypeAuth = (req) -> {
// 先校验提供的 grant_type 是否有效
String grantType = req.getParamNotNull(SaOAuth2Consts.Param.grant_type);
SaOAuth2GrantTypeHandlerInterface grantTypeHandler = grantTypeHandlerMap.get(grantType);
if(grantTypeHandler == null) {
throw new SaOAuth2Exception("无效 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
}
// 看看全局是否开启了此 grantType
// 针对 authorization_code 与 password 两种特殊 grant_type,需要判断全局是否开启
SaOAuth2ServerConfig config = SaOAuth2Manager.getServerConfig();
if(grantType.equals(GrantType.authorization_code) && !config.getEnableAuthorizationCode() ) {
throw new SaOAuth2Exception("系统未开放的 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
@@ -208,7 +210,7 @@ public final class SaOAuth2Strategy {
throw new SaOAuth2Exception("应用未开放的 grant_type: " + grantType).setCode(SaOAuth2ErrorCode.CODE_30141);
}
// 调用 处理器
// 调用 处理器构建 Access-Token
return grantTypeHandler.getAccessToken(req, clientIdAndSecretModel.getClientId(), scopes);
};
@@ -269,5 +271,20 @@ public final class SaOAuth2Strategy {
};
// ------------------ 其它 ------------------
/**
* 在创建 SaClientModel 时,设置其默认字段
*/
public SaParamFunction<SaClientModel> setSaClientModelDefaultFields = (clientModel) -> {
SaOAuth2ServerConfig config = SaOAuth2Manager.getServerConfig();
clientModel.accessTokenTimeout = config.getAccessTokenTimeout();
clientModel.refreshTokenTimeout = config.getRefreshTokenTimeout();
clientModel.clientTokenTimeout = config.getClientTokenTimeout();
clientModel.maxAccessTokenCount = config.getMaxAccessTokenCount();
clientModel.maxRefreshTokenCount = config.getMaxRefreshTokenCount();
clientModel.maxClientTokenCount = config.getMaxClientTokenCount();
clientModel.isNewRefresh = config.getIsNewRefresh();
};
}
@@ -37,7 +37,7 @@ import java.util.List;
*/
public class SaOAuth2Template {
// ----------------- ClientModel 相关 -----------------
// ----------------- SaClientModel 相关 -----------------
/**
* 获取 ClientModel,根据 clientId
@@ -65,7 +65,7 @@ public class SaOAuth2Template {
}
/**
* 校验:clientId 与 clientSecret 是否正确
* 校验:clientId 与 clientSecret 是否正确,正确返回 SaClientModel,不正确抛出异常
* @param clientId 应用id
* @param clientSecret 秘钥
* @return SaClientModel对象
@@ -287,6 +287,15 @@ public class SaOAuth2Template {
return !isGrantScope(loginId, clientId, scopes);
}
/**
* 删除:指定 loginId 针对指定 Client 的授权信息
* @param loginId 账号id
* @param clientId 应用id
*/
public void deleteGrantScope(Object loginId, String clientId) {
SaOAuth2Manager.getDao().deleteGrantScope(clientId, loginId);
}
// --------- 请求数据校验相关
@@ -337,10 +346,10 @@ public class SaOAuth2Template {
RefreshTokenModel rt = dao.getRefreshToken(refreshToken);
SaOAuth2RefreshTokenException.throwBy(rt == null, "无效 refresh_token: " + refreshToken, refreshToken, SaOAuth2ErrorCode.CODE_30111);
// 校验:ClientId是否一致
// 校验:ClientId 是否一致
SaOAuth2ClientModelException.throwBy( ! rt.clientId.equals(clientId), "无效 client_id: " + clientId, clientId, SaOAuth2ErrorCode.CODE_30122);
// 校验:Secret是否正确
// 校验:Secret 是否正确
String dbSecret = checkClientModel(clientId).clientSecret;
SaOAuth2ClientModelException.throwBy(dbSecret == null || ! dbSecret.equals(clientSecret), "无效 client_secret: " + clientSecret,
clientId, SaOAuth2ErrorCode.CODE_30115);
@@ -435,7 +444,7 @@ public class SaOAuth2Template {
* @return /
*/
public List<String> getAccessTokenValueList(String clientId, Object loginId) {
return SaOAuth2Manager.getDao().getAccessTokenValueList(clientId, loginId);
return SaOAuth2Manager.getDao().getAccessTokenValueList_FromAdjustAfter(clientId, loginId);
}
/**
@@ -503,7 +512,7 @@ public class SaOAuth2Template {
// 删 at、索引
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
dao.deleteAccessToken(accessToken);
dao.deleteAccessTokenIndexBySingleData(at.clientId, at.loginId, accessToken);
dao.deleteAccessTokenIndex_BySingleData(at.clientId, at.loginId, accessToken);
}
/**
@@ -560,7 +569,7 @@ public class SaOAuth2Template {
* @return /
*/
public List<String> getRefreshTokenValueList(String clientId, Object loginId) {
return SaOAuth2Manager.getDao().getRefreshTokenValueList(clientId, loginId);
return SaOAuth2Manager.getDao().getRefreshTokenValueList_FromAdjustAfter(clientId, loginId);
}
/**
@@ -577,7 +586,7 @@ public class SaOAuth2Template {
// 删 rt、索引
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
dao.deleteRefreshToken(refreshToken);
dao.deleteRefreshTokenIndexBySingleData(rt.clientId, rt.loginId, refreshToken);
dao.deleteRefreshTokenIndex_BySingleData(rt.clientId, rt.loginId, refreshToken);
}
/**
@@ -643,7 +652,7 @@ public class SaOAuth2Template {
* @return /
*/
public List<String> getClientTokenValueList(String clientId) {
return SaOAuth2Manager.getDao().getClientTokenValueList(clientId);
return SaOAuth2Manager.getDao().getClientTokenValueList_FromAdjustAfter(clientId);
}
/**
@@ -693,7 +702,7 @@ public class SaOAuth2Template {
// 删 ct、删索引
SaOAuth2Dao dao = SaOAuth2Manager.getDao();
dao.deleteClientToken(clientToken);
dao.deleteClientTokenIndexBySingleData(ct.clientId, clientToken);
dao.deleteClientTokenIndex_BySingleData(ct.clientId, clientToken);
}
/**
@@ -128,6 +128,15 @@ public class SaOAuth2Util {
return SaOAuth2Manager.getTemplate().isGrantScope(loginId, clientId, scopes);
}
/**
* 删除:指定 loginId 针对指定 Client 的授权信息
* @param loginId 账号id
* @param clientId 应用id
*/
public static void deleteGrantScope(Object loginId, String clientId) {
SaOAuth2Manager.getTemplate().deleteGrantScope(loginId, clientId);
}
// ----------------- Code 相关 -----------------