feat(oauth2): 新增 UnionId 联合id 实现

This commit is contained in:
click33 2024-11-28 08:26:58 +08:00
parent e7694bd6fb
commit 21d5e02c67
9 changed files with 126 additions and 10 deletions

View File

@ -187,7 +187,7 @@
client_id: '1001',
client_secret: 'aaaa-bbbb-cccc-dddd-eeee',
redirect_uri: location.href.split('?')[0].split('#')[0],
scope: 'userinfo,userid,openid,oidc',
scope: 'userinfo,userid,openid,unionid,oidc',
username: 'sa',
password: '123456'
}

View File

@ -27,7 +27,8 @@ public class SaClientMockDao {
.setClientId("1001") // client id
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee") // client 秘钥
.addAllowRedirectUris("*") // 所有允许授权的 url
.addContractScopes("openid", "userid", "userinfo", "oidc") // 所有签约的权限
.addContractScopes("openid", "unionid", "userid", "userinfo", "oidc") // 所有签约的权限
.setSubjectId("1000001") // 主体 id (可选)
.addAllowGrantTypes( // 所有允许的授权模式
GrantType.authorization_code, // 授权码式
GrantType.implicit, // 隐式式
@ -43,7 +44,8 @@ public class SaClientMockDao {
.setClientId("1002")
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee")
.addAllowRedirectUris("*")
.addContractScopes("openid", "userid", "userinfo", "oidc")
.addContractScopes("openid", "unionid", "userid", "userinfo", "oidc")
.setSubjectId("1000001") // 主体 id (可选)
.addAllowGrantTypes(
GrantType.authorization_code,
GrantType.implicit,
@ -58,7 +60,7 @@ public class SaClientMockDao {
.setClientId("1003")
.setClientSecret("aaaa-bbbb-cccc-dddd-eeee")
.addAllowRedirectUris("*")
.addContractScopes("openid", "userid", "userinfo", "oidc")
.addContractScopes("openid", "unionid", "userid", "userinfo", "oidc")
.addAllowGrantTypes(
GrantType.authorization_code,
GrantType.implicit,

View File

@ -69,6 +69,9 @@ public class SaOAuth2ServerConfig implements Serializable {
/** 默认 openid 生成算法中使用的摘要前缀 */
public String openidDigestPrefix = SaOAuth2Consts.OPENID_DEFAULT_DIGEST_PREFIX;
/** 默认 unionid 生成算法中使用的摘要前缀 */
public String unionidDigestPrefix = SaOAuth2Consts.UNIONID_DEFAULT_DIGEST_PREFIX;
/** 指定高级权限,多个用逗号隔开 */
public String higherScope;
@ -264,6 +267,22 @@ public class SaOAuth2ServerConfig implements Serializable {
return this;
}
/**
* @return unionidDigestPrefix
*/
public String getUnionidDigestPrefix() {
return unionidDigestPrefix;
}
/**
* @param unionidDigestPrefix 要设置的 unionidDigestPrefix
* @return 对象自身
*/
public SaOAuth2ServerConfig setUnionidDigestPrefix(String unionidDigestPrefix) {
this.unionidDigestPrefix = unionidDigestPrefix;
return this;
}
/**
* 获取 指定高级权限多个用逗号隔开
*
@ -403,6 +422,7 @@ public class SaOAuth2ServerConfig implements Serializable {
", clientTokenTimeout=" + clientTokenTimeout +
", lowerClientTokenTimeout=" + lowerClientTokenTimeout +
", openidDigestPrefix='" + openidDigestPrefix +
", unionidDigestPrefix='" + unionidDigestPrefix +
", higherScope='" + higherScope +
", lowerScope='" + lowerScope +
", mode4ReturnAccessToken='" + mode4ReturnAccessToken +

View File

@ -90,6 +90,7 @@ public class SaOAuth2Consts {
* 扩展字段
*/
public static final class ExtraField {
public static String unionid = "unionid";
public static String openid = "openid";
public static String userid = "userid";
public static String id_token = "id_token";
@ -99,6 +100,9 @@ public class SaOAuth2Consts {
/** 默认 openid 生成算法中使用的前缀 */
public static final String OPENID_DEFAULT_DIGEST_PREFIX = "openid_default_digest_prefix";
/** 默认 unionid 生成算法中使用的前缀 */
public static final String UNIONID_DEFAULT_DIGEST_PREFIX = "unionid_default_digest_prefix";
/** 表示OK的返回结果 */
public static final String OK = "ok";

View File

@ -57,7 +57,7 @@ public interface SaOAuth2DataLoader {
}
/**
* 根据ClientId LoginId 获取openid
* 根据 ClientId LoginId 获取openid
*
* @param clientId 应用id
* @param loginId 账号id
@ -67,4 +67,15 @@ public interface SaOAuth2DataLoader {
return SaSecureUtil.md5(SaOAuth2Manager.getServerConfig().getOpenidDigestPrefix() + "_" + clientId + "_" + loginId);
}
/**
* 根据 SubjectId LoginId 获取 unionid
*
* @param subjectId 应用主体id
* @param loginId 账号id
* @return 此账号在此Client下的openid
*/
default String getUnionid(String subjectId, Object loginId) {
return SaSecureUtil.md5(SaOAuth2Manager.getServerConfig().getUnionidDigestPrefix() + "_" + subjectId + "_" + loginId);
}
}

View File

@ -24,7 +24,7 @@ import java.util.Arrays;
import java.util.List;
/**
* Client应用信息 Model
* Client 应用信息 Model
*
* @author click33
* @since 1.23.0
@ -58,6 +58,11 @@ public class SaClientModel implements Serializable {
*/
public List<String> allowGrantTypes = new ArrayList<>();
/**
* 主体id
*/
public String subjectId;
/** 单独配置此Client是否在每次 Refresh-Token 刷新 Access-Token 时,产生一个新的 Refresh-Token [默认取全局配置] */
public Boolean isNewRefresh;
@ -171,6 +176,25 @@ public class SaClientModel implements Serializable {
return this;
}
/**
* 获取 主体id
*
* @return subjectId 主体id
*/
public String getSubjectId() {
return this.subjectId;
}
/**
* 设置 主体id
*
* @param subjectId 主体id
*/
public SaClientModel setSubjectId(String subjectId) {
this.subjectId = subjectId;
return this;
}
/**
* @return 此Client是否在每次 Refresh-Token 刷新 Access-Token 产生一个新的 Refresh-Token [默认取全局配置]
*/
@ -261,6 +285,7 @@ public class SaClientModel implements Serializable {
", contractScopes=" + contractScopes +
", allowRedirectUris=" + allowRedirectUris +
", allowGrantTypes=" + allowGrantTypes +
", subjectId=" + subjectId +
", isNewRefresh=" + isNewRefresh +
", accessTokenTimeout=" + accessTokenTimeout +
", refreshTokenTimeout=" + refreshTokenTimeout +

View File

@ -31,6 +31,11 @@ public final class CommonScope {
*/
public static final String OPENID = "openid";
/**
* 获取 unionid
*/
public static final String UNIONID = "unionid";
/**
* 获取 userid
*/

View File

@ -0,0 +1,51 @@
/*
* 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.handler;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.consts.SaOAuth2Consts;
import cn.dev33.satoken.oauth2.data.loader.SaOAuth2DataLoader;
import cn.dev33.satoken.oauth2.data.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.data.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.data.model.loader.SaClientModel;
import cn.dev33.satoken.oauth2.scope.CommonScope;
/**
* UnionId Scope 处理器在返回的 AccessToken 中增加 unionid 字段
*
* @author click33
* @since 1.40.0
*/
public class UnionIdScopeHandler implements SaOAuth2ScopeHandlerInterface {
@Override
public String getHandlerScope() {
return CommonScope.UNIONID;
}
@Override
public void workAccessToken(AccessTokenModel at) {
SaOAuth2DataLoader dataLoader = SaOAuth2Manager.getDataLoader();
SaClientModel cm = dataLoader.getClientModelNotNull(at.clientId);
at.extraData.put(SaOAuth2Consts.ExtraField.unionid, dataLoader.getUnionid(cm.subjectId, at.loginId));
}
@Override
public void workClientToken(ClientTokenModel ct) {
}
}

View File

@ -30,10 +30,7 @@ import cn.dev33.satoken.oauth2.granttype.handler.PasswordGrantTypeHandler;
import cn.dev33.satoken.oauth2.granttype.handler.RefreshTokenGrantTypeHandler;
import cn.dev33.satoken.oauth2.granttype.handler.SaOAuth2GrantTypeHandlerInterface;
import cn.dev33.satoken.oauth2.scope.CommonScope;
import cn.dev33.satoken.oauth2.scope.handler.OidcScopeHandler;
import cn.dev33.satoken.oauth2.scope.handler.OpenIdScopeHandler;
import cn.dev33.satoken.oauth2.scope.handler.SaOAuth2ScopeHandlerInterface;
import cn.dev33.satoken.oauth2.scope.handler.UserIdScopeHandler;
import cn.dev33.satoken.oauth2.scope.handler.*;
import cn.dev33.satoken.util.SaFoxUtil;
import java.util.LinkedHashMap;
@ -70,6 +67,7 @@ public final class SaOAuth2Strategy {
*/
public void registerDefaultScopeHandler() {
scopeHandlerMap.put(CommonScope.OPENID, new OpenIdScopeHandler());
scopeHandlerMap.put(CommonScope.UNIONID, new UnionIdScopeHandler());
scopeHandlerMap.put(CommonScope.USERID, new UserIdScopeHandler());
scopeHandlerMap.put(CommonScope.OIDC, new OidcScopeHandler());
}