diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java index 88b07412..1110aae4 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/SaOAuth2Manager.java @@ -16,6 +16,8 @@ package cn.dev33.satoken.oauth2; import cn.dev33.satoken.oauth2.config.SaOAuth2Config; +import cn.dev33.satoken.oauth2.dao.SaOAuth2Dao; +import cn.dev33.satoken.oauth2.dao.SaOAuth2DaoDefaultImpl; import cn.dev33.satoken.oauth2.data.convert.SaOAuth2DataConverter; import cn.dev33.satoken.oauth2.data.convert.SaOAuth2DataConverterDefaultImpl; import cn.dev33.satoken.oauth2.data.loader.SaOAuth2DataLoader; @@ -104,4 +106,22 @@ public class SaOAuth2Manager { SaOAuth2Manager.dataConverter = dataConverter; } + /** + * OAuth2 数据持久 Bean + */ + private static volatile SaOAuth2Dao dao; + public static SaOAuth2Dao getDao() { + if (dao == null) { + synchronized (SaOAuth2Manager.class) { + if (dao == null) { + setDao(new SaOAuth2DaoDefaultImpl()); + } + } + } + return dao; + } + public static void setDao(SaOAuth2Dao dao) { + SaOAuth2Manager.dao = dao; + } + } 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 new file mode 100644 index 00000000..209f8a55 --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2Dao.java @@ -0,0 +1,484 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.oauth2.dao; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.config.SaTokenConfig; +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.oauth2.SaOAuth2Manager; +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.util.SaFoxUtil; + +import java.util.List; + +/** + * Sa-Token OAuth2 数据持久层 + * + * @author click33 + * @since 1.39.0 + */ +public interface SaOAuth2Dao { + + // ------------------- save 数据 + + /** + * 持久化:Code-Model + * @param c . + */ + default void saveCode(CodeModel c) { + if(c == null) { + return; + } + getSaTokenDao().setObject(splicingCodeSaveKey(c.code), c, SaOAuth2Manager.getConfig().getCodeTimeout()); + } + + /** + * 持久化:Code-索引 + * @param c . + */ + default void saveCodeIndex(CodeModel c) { + if(c == null) { + return; + } + getSaTokenDao().set(splicingCodeIndexKey(c.clientId, c.loginId), c.code, SaOAuth2Manager.getConfig().getCodeTimeout()); + } + + /** + * 持久化:AccessToken-Model + * @param at . + */ + default void saveAccessToken(AccessTokenModel at) { + if(at == null) { + return; + } + getSaTokenDao().setObject(splicingAccessTokenSaveKey(at.accessToken), at, at.getExpiresIn()); + } + + /** + * 持久化:AccessToken-索引 + * @param at . + */ + default void saveAccessTokenIndex(AccessTokenModel at) { + if(at == null) { + return; + } + getSaTokenDao().set(splicingAccessTokenIndexKey(at.clientId, at.loginId), at.accessToken, at.getExpiresIn()); + } + + /** + * 持久化:RefreshToken-Model + * @param rt . + */ + default void saveRefreshToken(RefreshTokenModel rt) { + if(rt == null) { + return; + } + getSaTokenDao().setObject(splicingRefreshTokenSaveKey(rt.refreshToken), rt, rt.getExpiresIn()); + } + + /** + * 持久化:RefreshToken-索引 + * @param rt . + */ + default void saveRefreshTokenIndex(RefreshTokenModel rt) { + if(rt == null) { + return; + } + getSaTokenDao().set(splicingRefreshTokenIndexKey(rt.clientId, rt.loginId), rt.refreshToken, rt.getExpiresIn()); + } + + /** + * 持久化:ClientToken-Model + * @param ct . + */ + default void saveClientToken(ClientTokenModel ct) { + if(ct == null) { + return; + } + getSaTokenDao().setObject(splicingClientTokenSaveKey(ct.clientToken), ct, ct.getExpiresIn()); + } + + /** + * 持久化:ClientToken-索引 + * @param ct . + */ + default void saveClientTokenIndex(ClientTokenModel ct) { + if(ct == null) { + return; + } + getSaTokenDao().set(splicingClientTokenIndexKey(ct.clientId), ct.clientToken, ct.getExpiresIn()); + } + + /** + * 持久化:Past-Token-索引 + * @param ct / + */ + default void savePastTokenIndex(ClientTokenModel ct) { + if(ct == null) { + return; + } + long ttl = ct.getExpiresIn(); + // TODO PastToken ttl 是否有必要单独配置个字段? +// SaClientModel cm = checkClientModel(ct.clientId); +// if (cm.getPastClientTokenTimeout() != -1) { +// ttl = cm.getPastClientTokenTimeout(); +// } + getSaTokenDao().set(splicingPastTokenIndexKey(ct.clientId), ct.clientToken, ttl); + } + + /** + * 持久化:用户授权记录 + * @param clientId 应用id + * @param loginId 账号id + * @param scopes 权限列表 + */ + default void saveGrantScope(String clientId, Object loginId, List scopes) { + if( ! SaFoxUtil.isEmpty(scopes)) { + // TODO ttl 计算规则优化 + long ttl = SaOAuth2Manager.getConfig().getAccessTokenTimeout(); + // long ttl = checkClientModel(clientId).getAccessTokenTimeout(); + String value = SaOAuth2Manager.getDataConverter().convertScopeListToString(scopes); + getSaTokenDao().set(splicingGrantScopeKey(clientId, loginId), value, ttl); + } + } + + + // ------------------- delete数据 + + /** + * 删除:Code + * @param code 值 + */ + default void deleteCode(String code) { + if(code != null) { + getSaTokenDao().deleteObject(splicingCodeSaveKey(code)); + } + } + + /** + * 删除:Code索引 + * @param clientId 应用id + * @param loginId 账号id + */ + default void deleteCodeIndex(String clientId, Object loginId) { + getSaTokenDao().delete(splicingCodeIndexKey(clientId, loginId)); + } + + /** + * 删除:Access-Token + * @param accessToken 值 + */ + default void deleteAccessToken(String accessToken) { + if(accessToken != null) { + getSaTokenDao().deleteObject(splicingAccessTokenSaveKey(accessToken)); + } + } + + /** + * 删除:Access-Token索引 + * @param clientId 应用id + * @param loginId 账号id + */ + default void deleteAccessTokenIndex(String clientId, Object loginId) { + getSaTokenDao().delete(splicingAccessTokenIndexKey(clientId, loginId)); + } + + /** + * 删除:Refresh-Token + * @param refreshToken 值 + */ + default void deleteRefreshToken(String refreshToken) { + if(refreshToken != null) { + getSaTokenDao().deleteObject(splicingRefreshTokenSaveKey(refreshToken)); + } + } + + /** + * 删除:Refresh-Token索引 + * @param clientId 应用id + * @param loginId 账号id + */ + default void deleteRefreshTokenIndex(String clientId, Object loginId) { + getSaTokenDao().delete(splicingRefreshTokenIndexKey(clientId, loginId)); + } + + /** + * 删除:Client-Token + * @param clientToken 值 + */ + default void deleteClientToken(String clientToken) { + if(clientToken != null) { + getSaTokenDao().deleteObject(splicingClientTokenSaveKey(clientToken)); + } + } + + /** + * 删除:Client-Token索引 + * @param clientId 应用id + */ + default void deleteClientTokenIndex(String clientId) { + getSaTokenDao().delete(splicingClientTokenIndexKey(clientId)); + } + + /** + * 删除:Past-Token索引 + * @param clientId 应用id + */ + default void deletePastTokenIndex(String clientId) { + getSaTokenDao().delete(splicingPastTokenIndexKey(clientId)); + } + + /** + * 删除:用户授权记录 + * @param clientId 应用id + * @param loginId 账号id + */ + default void deleteGrantScope(String clientId, Object loginId) { + getSaTokenDao().delete(splicingGrantScopeKey(clientId, loginId)); + } + + + // ------------------- get 数据 + + /** + * 获取:Code Model + * @param code . + * @return . + */ + default CodeModel getCode(String code) { + if(code == null) { + return null; + } + return (CodeModel)getSaTokenDao().getObject(splicingCodeSaveKey(code)); + } + + /** + * 获取:Code Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + default String getCodeValue(String clientId, Object loginId) { + return getSaTokenDao().get(splicingCodeIndexKey(clientId, loginId)); + } + + /** + * 获取:Access-Token Model + * @param accessToken . + * @return . + */ + default AccessTokenModel getAccessToken(String accessToken) { + if(accessToken == null) { + return null; + } + return (AccessTokenModel)getSaTokenDao().getObject(splicingAccessTokenSaveKey(accessToken)); + } + + /** + * 获取:Access-Token Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + default String getAccessTokenValue(String clientId, Object loginId) { + return getSaTokenDao().get(splicingAccessTokenIndexKey(clientId, loginId)); + } + + /** + * 获取:Refresh-Token Model + * @param refreshToken . + * @return . + */ + default RefreshTokenModel getRefreshToken(String refreshToken) { + if(refreshToken == null) { + return null; + } + return (RefreshTokenModel)getSaTokenDao().getObject(splicingRefreshTokenSaveKey(refreshToken)); + } + + /** + * 获取:Refresh-Token Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + default String getRefreshTokenValue(String clientId, Object loginId) { + return getSaTokenDao().get(splicingRefreshTokenIndexKey(clientId, loginId)); + } + + /** + * 获取:Client-Token Model + * @param clientToken . + * @return . + */ + default ClientTokenModel getClientToken(String clientToken) { + if(clientToken == null) { + return null; + } + return (ClientTokenModel)getSaTokenDao().getObject(splicingClientTokenSaveKey(clientToken)); + } + + /** + * 获取:Client-Token Value + * @param clientId 应用id + * @return . + */ + default String getClientTokenValue(String clientId) { + return getSaTokenDao().get(splicingClientTokenIndexKey(clientId)); + } + + /** + * 获取:Past-Token Value + * @param clientId 应用id + * @return . + */ + default String getPastTokenValue(String clientId) { + return getSaTokenDao().get(splicingPastTokenIndexKey(clientId)); + } + + /** + * 获取:用户授权记录 + * @param clientId 应用id + * @param loginId 账号id + * @return 权限 + */ + default List getGrantScope(String clientId, Object loginId) { + String value = getSaTokenDao().get(splicingGrantScopeKey(clientId, loginId)); + return SaOAuth2Manager.getDataConverter().convertScopeStringToList(value); + } + + + // ------------------- 拼接key + + /** + * 拼接key:Code持久化 + * @param code 授权码 + * @return key + */ + default String splicingCodeSaveKey(String code) { + return getSaTokenConfig().getTokenName() + ":oauth2:code:" + code; + } + + /** + * 拼接key:Code索引 + * @param clientId 应用id + * @param loginId 账号id + * @return key + */ + default String splicingCodeIndexKey(String clientId, Object loginId) { + return getSaTokenConfig().getTokenName() + ":oauth2:code-index:" + clientId + ":" + loginId; + } + + /** + * 拼接key:Access-Token持久化 + * @param accessToken accessToken + * @return key + */ + default String splicingAccessTokenSaveKey(String accessToken) { + return getSaTokenConfig().getTokenName() + ":oauth2:access-token:" + accessToken; + } + + /** + * 拼接key:Access-Token索引 + * @param clientId 应用id + * @param loginId 账号id + * @return key + */ + default String splicingAccessTokenIndexKey(String clientId, Object loginId) { + return getSaTokenConfig().getTokenName() + ":oauth2:access-token-index:" + clientId + ":" + loginId; + } + + /** + * 拼接key:Refresh-Token持久化 + * @param refreshToken refreshToken + * @return key + */ + default String splicingRefreshTokenSaveKey(String refreshToken) { + return getSaTokenConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken; + } + + /** + * 拼接key:Refresh-Token索引 + * @param clientId 应用id + * @param loginId 账号id + * @return key + */ + default String splicingRefreshTokenIndexKey(String clientId, Object loginId) { + return getSaTokenConfig().getTokenName() + ":oauth2:refresh-token-index:" + clientId + ":" + loginId; + } + + /** + * 拼接key:Client-Token持久化 + * @param clientToken clientToken + * @return key + */ + default String splicingClientTokenSaveKey(String clientToken) { + return getSaTokenConfig().getTokenName() + ":oauth2:client-token:" + clientToken; + } + + /** + * 拼接key:Client-Token 索引 + * @param clientId clientId + * @return key + */ + default String splicingClientTokenIndexKey(String clientId) { + return getSaTokenConfig().getTokenName() + ":oauth2:client-token-index:" + clientId; + } + + /** + * 拼接key:Past-Token 索引 + * @param clientId clientId + * @return key + */ + default String splicingPastTokenIndexKey(String clientId) { + return getSaTokenConfig().getTokenName() + ":oauth2:past-token-index:" + clientId; + } + + /** + * 拼接key:用户授权记录 + * @param clientId 应用id + * @param loginId 账号id + * @return key + */ + default String splicingGrantScopeKey(String clientId, Object loginId) { + return getSaTokenConfig().getTokenName() + ":oauth2:grant-scope:" + clientId + ":" + loginId; + } + + + // -------- bean 对象代理 + + /** + * 获取使用的 getSaTokenDao 实例 + * + * @return / + */ + default SaTokenDao getSaTokenDao() { + return SaManager.getSaTokenDao(); + } + + /** + * 获取使用的 SaTokenConfig 实例 + * + * @return / + */ + default SaTokenConfig getSaTokenConfig() { + return SaManager.getConfig(); + } + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2DaoDefaultImpl.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2DaoDefaultImpl.java new file mode 100644 index 00000000..0ebd09f2 --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/dao/SaOAuth2DaoDefaultImpl.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.oauth2.dao; + +/** + * Sa-Token OAuth2 数据持久层,默认实现 + * + * @author click33 + * @since 1.39.0 + */ +public class SaOAuth2DaoDefaultImpl implements SaOAuth2Dao { + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/CommonScope.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/CommonScope.java new file mode 100644 index 00000000..e64892db --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/scope/CommonScope.java @@ -0,0 +1,44 @@ +/* + * Copyright 2020-2099 sa-token.cc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.dev33.satoken.oauth2.scope; + +/** + * OAuth2 常见权限定义 + * + * @author click33 + * @since 1.39.0 + */ +public final class CommonScope { + + private CommonScope() { + } + + /** + * 获取 openid + */ + public static final String OPENID = "openid"; + + /** + * 获取用户信息 + */ + public static final String USERINFO = "userinfo"; + + /** + * 获取 id_token + */ + public static final String OIDC = "oidc"; + +} \ No newline at end of file diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java index cf9e1bd1..df9fc99f 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java @@ -15,10 +15,10 @@ */ package cn.dev33.satoken.oauth2.template; -import cn.dev33.satoken.SaManager; import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.oauth2.SaOAuth2Manager; import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts.Param; +import cn.dev33.satoken.oauth2.dao.SaOAuth2Dao; import cn.dev33.satoken.oauth2.data.model.*; import cn.dev33.satoken.oauth2.error.SaOAuth2ErrorCode; import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception; @@ -76,7 +76,7 @@ public class SaOAuth2Template { * @return . */ public AccessTokenModel checkAccessToken(String accessToken) { - AccessTokenModel at = getAccessToken(accessToken); + AccessTokenModel at = SaOAuth2Manager.getDao().getAccessToken(accessToken); SaOAuth2Exception.throwBy(at == null, "无效access_token:" + accessToken, SaOAuth2ErrorCode.CODE_30106); return at; } @@ -86,7 +86,7 @@ public class SaOAuth2Template { * @return . */ public ClientTokenModel checkClientToken(String clientToken) { - ClientTokenModel ct = getClientToken(clientToken); + ClientTokenModel ct = SaOAuth2Manager.getDao().getClientToken(clientToken); SaOAuth2Exception.throwBy(ct == null, "无效:client_token" + clientToken, SaOAuth2ErrorCode.CODE_30107); return ct; } @@ -155,16 +155,19 @@ public class SaOAuth2Template { */ public CodeModel generateCode(RequestAuthModel ra) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 删除旧Code - deleteCode(getCodeValue(ra.clientId, ra.loginId)); + String oldCodeValue = SaOAuth2Manager.getDao().getCodeValue(ra.clientId, ra.loginId); + dao.deleteCode(oldCodeValue); // 生成新Code - String code = randomCode(ra.clientId, ra.loginId, ra.scopes); - CodeModel cm = new CodeModel(code, ra.clientId, ra.scopes, ra.loginId, ra.redirectUri); + String codeValue = randomCode(ra.clientId, ra.loginId, ra.scopes); + CodeModel cm = new CodeModel(codeValue, ra.clientId, ra.scopes, ra.loginId, ra.redirectUri); // 保存新Code - saveCode(cm); - saveCodeIndex(cm); + dao.saveCode(cm); + dao.saveCodeIndex(cm); // 返回 return cm; @@ -176,13 +179,15 @@ public class SaOAuth2Template { */ public AccessTokenModel generateAccessToken(String code) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 1、先校验 - CodeModel cm = getCode(code); + CodeModel cm = dao.getCode(code); SaOAuth2Exception.throwBy(cm == null, "无效code", SaOAuth2ErrorCode.CODE_30110); // 2、删除旧Token - deleteAccessToken(getAccessTokenValue(cm.clientId, cm.loginId)); - deleteRefreshToken(getRefreshTokenValue(cm.clientId, cm.loginId)); + dao.deleteAccessToken(dao.getAccessTokenValue(cm.clientId, cm.loginId)); + dao.deleteRefreshToken(dao.getRefreshTokenValue(cm.clientId, cm.loginId)); // 3、生成token AccessTokenModel at = convertCodeToAccessToken(cm); @@ -191,14 +196,14 @@ public class SaOAuth2Template { at.refreshExpiresTime = rt.expiresTime; // 4、保存token - saveAccessToken(at); - saveAccessTokenIndex(at); - saveRefreshToken(rt); - saveRefreshTokenIndex(rt); + dao.saveAccessToken(at); + dao.saveAccessTokenIndex(at); + dao.saveRefreshToken(rt); + dao.saveRefreshTokenIndex(rt); // 5、删除此Code - deleteCode(code); - deleteCodeIndex(cm.clientId, cm.loginId); + dao.deleteCode(code); + dao.deleteCodeIndex(cm.clientId, cm.loginId); // 6、返回 Access-Token return at; @@ -210,30 +215,32 @@ public class SaOAuth2Template { */ public AccessTokenModel refreshAccessToken(String refreshToken) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 获取 Refresh-Token 信息 - RefreshTokenModel rt = getRefreshToken(refreshToken); + RefreshTokenModel rt = dao.getRefreshToken(refreshToken); SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken, SaOAuth2ErrorCode.CODE_30111); // 如果配置了[每次刷新产生新的Refresh-Token] if(checkClientModel(rt.clientId).getIsNewRefresh()) { // 删除旧 Refresh-Token - deleteRefreshToken(rt.refreshToken); + dao.deleteRefreshToken(rt.refreshToken); // 创建并保持新的 Refresh-Token rt = convertRefreshTokenToRefreshToken(rt); - saveRefreshToken(rt); - saveRefreshTokenIndex(rt); + dao.saveRefreshToken(rt); + dao.saveRefreshTokenIndex(rt); } // 删除旧 Access-Token - deleteAccessToken(getAccessTokenValue(rt.clientId, rt.loginId)); + dao.deleteAccessToken(dao.getAccessTokenValue(rt.clientId, rt.loginId)); // 生成新 Access-Token AccessTokenModel at = convertRefreshTokenToAccessToken(rt); // 保存新 Access-Token - saveAccessToken(at); - saveAccessTokenIndex(at); + dao.saveAccessToken(at); + dao.saveAccessTokenIndex(at); // 返回新 Access-Token return at; @@ -246,10 +253,12 @@ public class SaOAuth2Template { */ public AccessTokenModel generateAccessToken(RequestAuthModel ra, boolean isCreateRt) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 1、删除 旧Token - deleteAccessToken(getAccessTokenValue(ra.clientId, ra.loginId)); + dao.deleteAccessToken(dao.getAccessTokenValue(ra.clientId, ra.loginId)); if(isCreateRt) { - deleteRefreshToken(getRefreshTokenValue(ra.clientId, ra.loginId)); + dao.deleteRefreshToken(dao.getRefreshTokenValue(ra.clientId, ra.loginId)); } // 2、生成 新Access-Token @@ -261,13 +270,13 @@ public class SaOAuth2Template { // 3、生成&保存 Refresh-Token if(isCreateRt) { RefreshTokenModel rt = convertAccessTokenToRefreshToken(at); - saveRefreshToken(rt); - saveRefreshTokenIndex(rt); + dao.saveRefreshToken(rt); + dao.saveRefreshTokenIndex(rt); } // 5、保存 新Access-Token - saveAccessToken(at); - saveAccessTokenIndex(at); + dao.saveAccessToken(at); + dao.saveAccessTokenIndex(at); // 6、返回 新Access-Token return at; @@ -279,18 +288,21 @@ public class SaOAuth2Template { * @return Client-Token Model */ public ClientTokenModel generateClientToken(String clientId, List scopes) { + + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 1、删掉旧 Past-Token - deleteClientToken(getPastTokenValue(clientId)); + dao.deleteClientToken(dao.getPastTokenValue(clientId)); // 2、将旧Client-Token 标记为新 Past-Token - ClientTokenModel oldCt = getClientToken(getClientTokenValue(clientId)); - savePastTokenIndex(oldCt); - + ClientTokenModel oldCt = dao.getClientToken(dao.getClientTokenValue(clientId)); + dao.savePastTokenIndex(oldCt); + // 2.5、如果配置了 PastClientToken 的 ttl ,则需要更新一下 SaClientModel cm = checkClientModel(clientId); if(oldCt != null && cm.getPastClientTokenTimeout() != -1) { oldCt.expiresTime = System.currentTimeMillis() + (cm.getPastClientTokenTimeout() * 1000); - saveClientToken(oldCt); + dao.saveClientToken(oldCt); } // 3、生成新Client-Token @@ -298,8 +310,8 @@ public class SaOAuth2Template { ct.expiresTime = System.currentTimeMillis() + (cm.getClientTokenTimeout() * 1000); // 3、保存新Client-Token - saveClientToken(ct); - saveClientTokenIndex(ct); + dao.saveClientToken(ct); + dao.saveClientTokenIndex(ct); // 4、返回 return ct; @@ -338,20 +350,22 @@ public class SaOAuth2Template { */ public void revokeAccessToken(String accessToken) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 如果查不到任何东西, 直接返回 - AccessTokenModel at = getAccessToken(accessToken); + AccessTokenModel at = dao.getAccessToken(accessToken); if(at == null) { return; } // 删除 Access-Token - deleteAccessToken(accessToken); - deleteAccessTokenIndex(at.clientId, at.loginId); + dao.deleteAccessToken(accessToken); + dao.deleteAccessTokenIndex(at.clientId, at.loginId); // 删除对应的 Refresh-Token - String refreshToken = getRefreshTokenValue(at.clientId, at.loginId); - deleteRefreshToken(refreshToken); - deleteRefreshTokenIndex(at.clientId, at.loginId); + String refreshToken = dao.getRefreshTokenValue(at.clientId, at.loginId); + dao.deleteRefreshToken(refreshToken); + dao.deleteRefreshTokenIndex(at.clientId, at.loginId); } // ------------------- check 数据校验 @@ -363,7 +377,8 @@ public class SaOAuth2Template { * @return 是否已经授权 */ public boolean isGrant(Object loginId, String clientId, List scopes) { - List grantScopeList = getGrantScope(clientId, loginId); + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + List grantScopeList = dao.getGrantScope(clientId, loginId); return scopes.isEmpty() || new HashSet<>(grantScopeList).containsAll(scopes); } /** @@ -511,8 +526,10 @@ public class SaOAuth2Template { */ public CodeModel checkGainTokenParam(String code, String clientId, String clientSecret, String redirectUri) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 校验:Code是否存在 - CodeModel cm = getCode(code); + CodeModel cm = dao.getCode(code); SaOAuth2Exception.throwBy(cm == null, "无效code: " + code, SaOAuth2ErrorCode.CODE_30117); // 校验:ClientId是否一致 @@ -539,8 +556,10 @@ public class SaOAuth2Template { */ public RefreshTokenModel checkRefreshTokenParam(String clientId, String clientSecret, String refreshToken) { + SaOAuth2Dao dao = SaOAuth2Manager.getDao(); + // 校验:Refresh-Token是否存在 - RefreshTokenModel rt = getRefreshToken(refreshToken); + RefreshTokenModel rt = dao.getRefreshToken(refreshToken); SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken, SaOAuth2ErrorCode.CODE_30121); // 校验:ClientId是否一致 @@ -636,299 +655,6 @@ public class SaOAuth2Template { return newRt; } - // ------------------- save 数据 - /** - * 持久化:Code-Model - * @param c . - */ - public void saveCode(CodeModel c) { - if(c == null) { - return; - } - SaManager.getSaTokenDao().setObject(splicingCodeSaveKey(c.code), c, SaOAuth2Manager.getConfig().getCodeTimeout()); - } - /** - * 持久化:Code-索引 - * @param c . - */ - public void saveCodeIndex(CodeModel c) { - if(c == null) { - return; - } - SaManager.getSaTokenDao().set(splicingCodeIndexKey(c.clientId, c.loginId), c.code, SaOAuth2Manager.getConfig().getCodeTimeout()); - } - /** - * 持久化:AccessToken-Model - * @param at . - */ - public void saveAccessToken(AccessTokenModel at) { - if(at == null) { - return; - } - SaManager.getSaTokenDao().setObject(splicingAccessTokenSaveKey(at.accessToken), at, at.getExpiresIn()); - } - /** - * 持久化:AccessToken-索引 - * @param at . - */ - public void saveAccessTokenIndex(AccessTokenModel at) { - if(at == null) { - return; - } - SaManager.getSaTokenDao().set(splicingAccessTokenIndexKey(at.clientId, at.loginId), at.accessToken, at.getExpiresIn()); - } - /** - * 持久化:RefreshToken-Model - * @param rt . - */ - public void saveRefreshToken(RefreshTokenModel rt) { - if(rt == null) { - return; - } - SaManager.getSaTokenDao().setObject(splicingRefreshTokenSaveKey(rt.refreshToken), rt, rt.getExpiresIn()); - } - /** - * 持久化:RefreshToken-索引 - * @param rt . - */ - public void saveRefreshTokenIndex(RefreshTokenModel rt) { - if(rt == null) { - return; - } - SaManager.getSaTokenDao().set(splicingRefreshTokenIndexKey(rt.clientId, rt.loginId), rt.refreshToken, rt.getExpiresIn()); - } - /** - * 持久化:ClientToken-Model - * @param ct . - */ - public void saveClientToken(ClientTokenModel ct) { - if(ct == null) { - return; - } - SaManager.getSaTokenDao().setObject(splicingClientTokenSaveKey(ct.clientToken), ct, ct.getExpiresIn()); - } - /** - * 持久化:ClientToken-索引 - * @param ct . - */ - public void saveClientTokenIndex(ClientTokenModel ct) { - if(ct == null) { - return; - } - SaManager.getSaTokenDao().set(splicingClientTokenIndexKey(ct.clientId), ct.clientToken, ct.getExpiresIn()); - } - /** - * 持久化:Past-Token-索引 - * @param ct . - */ - public void savePastTokenIndex(ClientTokenModel ct) { - if(ct == null) { - return; - } - long ttl = ct.getExpiresIn(); - SaClientModel cm = checkClientModel(ct.clientId); - if (cm.getPastClientTokenTimeout() != -1) { - ttl = cm.getPastClientTokenTimeout(); - } - SaManager.getSaTokenDao().set(splicingPastTokenIndexKey(ct.clientId), ct.clientToken, ttl); - } - /** - * 持久化:用户授权记录 - * @param clientId 应用id - * @param loginId 账号id - * @param scopes 权限列表 - */ - public void saveGrantScope(String clientId, Object loginId, List scopes) { - if( ! SaFoxUtil.isEmpty(scopes)) { - long ttl = checkClientModel(clientId).getAccessTokenTimeout(); - String value = SaOAuth2Manager.getDataConverter().convertScopeListToString(scopes); - SaManager.getSaTokenDao().set(splicingGrantScopeKey(clientId, loginId), value, ttl); - } - } - - // ------------------- get 数据 - /** - * 获取:Code Model - * @param code . - * @return . - */ - public CodeModel getCode(String code) { - if(code == null) { - return null; - } - return (CodeModel)SaManager.getSaTokenDao().getObject(splicingCodeSaveKey(code)); - } - /** - * 获取:Code Value - * @param clientId 应用id - * @param loginId 账号id - * @return . - */ - public String getCodeValue(String clientId, Object loginId) { - return SaManager.getSaTokenDao().get(splicingCodeIndexKey(clientId, loginId)); - } - /** - * 获取:Access-Token Model - * @param accessToken . - * @return . - */ - public AccessTokenModel getAccessToken(String accessToken) { - if(accessToken == null) { - return null; - } - return (AccessTokenModel)SaManager.getSaTokenDao().getObject(splicingAccessTokenSaveKey(accessToken)); - } - /** - * 获取:Access-Token Value - * @param clientId 应用id - * @param loginId 账号id - * @return . - */ - public String getAccessTokenValue(String clientId, Object loginId) { - return SaManager.getSaTokenDao().get(splicingAccessTokenIndexKey(clientId, loginId)); - } - /** - * 获取:Refresh-Token Model - * @param refreshToken . - * @return . - */ - public RefreshTokenModel getRefreshToken(String refreshToken) { - if(refreshToken == null) { - return null; - } - return (RefreshTokenModel)SaManager.getSaTokenDao().getObject(splicingRefreshTokenSaveKey(refreshToken)); - } - /** - * 获取:Refresh-Token Value - * @param clientId 应用id - * @param loginId 账号id - * @return . - */ - public String getRefreshTokenValue(String clientId, Object loginId) { - return SaManager.getSaTokenDao().get(splicingRefreshTokenIndexKey(clientId, loginId)); - } - /** - * 获取:Client-Token Model - * @param clientToken . - * @return . - */ - public ClientTokenModel getClientToken(String clientToken) { - if(clientToken == null) { - return null; - } - return (ClientTokenModel)SaManager.getSaTokenDao().getObject(splicingClientTokenSaveKey(clientToken)); - } - /** - * 获取:Client-Token Value - * @param clientId 应用id - * @return . - */ - public String getClientTokenValue(String clientId) { - return SaManager.getSaTokenDao().get(splicingClientTokenIndexKey(clientId)); - } - /** - * 获取:Past-Token Value - * @param clientId 应用id - * @return . - */ - public String getPastTokenValue(String clientId) { - return SaManager.getSaTokenDao().get(splicingPastTokenIndexKey(clientId)); - } - /** - * 获取:用户授权记录 - * @param clientId 应用id - * @param loginId 账号id - * @return 权限 - */ - public List getGrantScope(String clientId, Object loginId) { - String value = SaManager.getSaTokenDao().get(splicingGrantScopeKey(clientId, loginId)); - return SaOAuth2Manager.getDataConverter().convertScopeStringToList(value); - } - - // ------------------- delete数据 - /** - * 删除:Code - * @param code 值 - */ - public void deleteCode(String code) { - if(code != null) { - SaManager.getSaTokenDao().deleteObject(splicingCodeSaveKey(code)); - } - } - /** - * 删除:Code索引 - * @param clientId 应用id - * @param loginId 账号id - */ - public void deleteCodeIndex(String clientId, Object loginId) { - SaManager.getSaTokenDao().delete(splicingCodeIndexKey(clientId, loginId)); - } - /** - * 删除:Access-Token - * @param accessToken 值 - */ - public void deleteAccessToken(String accessToken) { - if(accessToken != null) { - SaManager.getSaTokenDao().deleteObject(splicingAccessTokenSaveKey(accessToken)); - } - } - /** - * 删除:Access-Token索引 - * @param clientId 应用id - * @param loginId 账号id - */ - public void deleteAccessTokenIndex(String clientId, Object loginId) { - SaManager.getSaTokenDao().delete(splicingAccessTokenIndexKey(clientId, loginId)); - } - /** - * 删除:Refresh-Token - * @param refreshToken 值 - */ - public void deleteRefreshToken(String refreshToken) { - if(refreshToken != null) { - SaManager.getSaTokenDao().deleteObject(splicingRefreshTokenSaveKey(refreshToken)); - } - } - /** - * 删除:Refresh-Token索引 - * @param clientId 应用id - * @param loginId 账号id - */ - public void deleteRefreshTokenIndex(String clientId, Object loginId) { - SaManager.getSaTokenDao().delete(splicingRefreshTokenIndexKey(clientId, loginId)); - } - /** - * 删除:Client-Token - * @param clientToken 值 - */ - public void deleteClientToken(String clientToken) { - if(clientToken != null) { - SaManager.getSaTokenDao().deleteObject(splicingClientTokenSaveKey(clientToken)); - } - } - /** - * 删除:Client-Token索引 - * @param clientId 应用id - */ - public void deleteClientTokenIndex(String clientId) { - SaManager.getSaTokenDao().delete(splicingClientTokenIndexKey(clientId)); - } - /** - * 删除:Past-Token索引 - * @param clientId 应用id - */ - public void deletePastTokenIndex(String clientId) { - SaManager.getSaTokenDao().delete(splicingPastTokenIndexKey(clientId)); - } - /** - * 删除:用户授权记录 - * @param clientId 应用id - * @param loginId 账号id - */ - public void deleteGrantScope(String clientId, Object loginId) { - SaManager.getSaTokenDao().delete(splicingGrantScopeKey(clientId, loginId)); - } - // ------------------- Random数据 /** * 随机一个 Code @@ -970,90 +696,30 @@ public class SaOAuth2Template { return SaFoxUtil.getRandomString(60); } - // ------------------- 拼接key + + // ------------------- 包装其它 bean 的方法 + /** - * 拼接key:Code持久化 - * @param code 授权码 - * @return key + * 获取:Access-Token Model + * @param accessToken / + * @return / */ - public String splicingCodeSaveKey(String code) { - return SaManager.getConfig().getTokenName() + ":oauth2:code:" + code; - } - /** - * 拼接key:Code索引 - * @param clientId 应用id - * @param loginId 账号id - * @return key - */ - public String splicingCodeIndexKey(String clientId, Object loginId) { - return SaManager.getConfig().getTokenName() + ":oauth2:code-index:" + clientId + ":" + loginId; - } - /** - * 拼接key:Access-Token持久化 - * @param accessToken accessToken - * @return key - */ - public String splicingAccessTokenSaveKey(String accessToken) { - return SaManager.getConfig().getTokenName() + ":oauth2:access-token:" + accessToken; - } - /** - * 拼接key:Access-Token索引 - * @param clientId 应用id - * @param loginId 账号id - * @return key - */ - public String splicingAccessTokenIndexKey(String clientId, Object loginId) { - return SaManager.getConfig().getTokenName() + ":oauth2:access-token-index:" + clientId + ":" + loginId; - } - /** - * 拼接key:Refresh-Token持久化 - * @param refreshToken refreshToken - * @return key - */ - public String splicingRefreshTokenSaveKey(String refreshToken) { - return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken; - } - /** - * 拼接key:Refresh-Token索引 - * @param clientId 应用id - * @param loginId 账号id - * @return key - */ - public String splicingRefreshTokenIndexKey(String clientId, Object loginId) { - return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token-index:" + clientId + ":" + loginId; - } - /** - * 拼接key:Client-Token持久化 - * @param clientToken clientToken - * @return key - */ - public String splicingClientTokenSaveKey(String clientToken) { - return SaManager.getConfig().getTokenName() + ":oauth2:client-token:" + clientToken; - } - /** - * 拼接key:Client-Token 索引 - * @param clientId clientId - * @return key - */ - public String splicingClientTokenIndexKey(String clientId) { - return SaManager.getConfig().getTokenName() + ":oauth2:client-token-index:" + clientId; - } - /** - * 拼接key:Past-Token 索引 - * @param clientId clientId - * @return key - */ - public String splicingPastTokenIndexKey(String clientId) { - return SaManager.getConfig().getTokenName() + ":oauth2:past-token-index:" + clientId; - } - /** - * 拼接key:用户授权记录 - * @param clientId 应用id - * @param loginId 账号id - * @return key - */ - public String splicingGrantScopeKey(String clientId, Object loginId) { - return SaManager.getConfig().getTokenName() + ":oauth2:grant-scope:" + clientId + ":" + loginId; + public AccessTokenModel getAccessToken(String accessToken) { + return SaOAuth2Manager.getDao().getAccessToken(accessToken); } + /** + * 持久化:用户授权记录 + * @param clientId 应用id + * @param loginId 账号id + * @param scopes 权限列表 + */ + public void saveGrantScope(String clientId, Object loginId, List scopes) { + SaOAuth2Manager.getDao().saveGrantScope(clientId, loginId, scopes); + } + + + + + } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Util.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Util.java index d7886714..beb1b3ac 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Util.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Util.java @@ -16,6 +16,7 @@ package cn.dev33.satoken.oauth2.template; import cn.dev33.satoken.context.model.SaRequest; +import cn.dev33.satoken.oauth2.SaOAuth2Manager; import cn.dev33.satoken.oauth2.data.model.*; import cn.dev33.satoken.oauth2.processor.SaOAuth2ServerProcessor; @@ -281,7 +282,7 @@ public class SaOAuth2Util { * @return . */ public static CodeModel getCode(String code) { - return SaOAuth2ServerProcessor.instance.oauth2Template.getCode(code); + return SaOAuth2Manager.getDao().getCode(code); } /** @@ -290,7 +291,7 @@ public class SaOAuth2Util { * @return . */ public static AccessTokenModel getAccessToken(String accessToken) { - return SaOAuth2ServerProcessor.instance.oauth2Template.getAccessToken(accessToken); + return SaOAuth2Manager.getDao().getAccessToken(accessToken); } /** @@ -299,7 +300,7 @@ public class SaOAuth2Util { * @return . */ public static RefreshTokenModel getRefreshToken(String refreshToken) { - return SaOAuth2ServerProcessor.instance.oauth2Template.getRefreshToken(refreshToken); + return SaOAuth2Manager.getDao().getRefreshToken(refreshToken); } /** @@ -308,7 +309,7 @@ public class SaOAuth2Util { * @return . */ public static ClientTokenModel getClientToken(String clientToken) { - return SaOAuth2ServerProcessor.instance.oauth2Template.getClientToken(clientToken); + return SaOAuth2Manager.getDao().getClientToken(clientToken); } /** @@ -318,7 +319,7 @@ public class SaOAuth2Util { * @return 权限 */ public static List getGrantScope(String clientId, Object loginId) { - return SaOAuth2ServerProcessor.instance.oauth2Template.getGrantScope(clientId, loginId); + return SaOAuth2Manager.getDao().getGrantScope(clientId, loginId); } }