mirror of
https://gitee.com/xiaonuobase/snowy.git
synced 2026-10-06 06:52:58 +08:00
【底座】采纳 #IJYGL1 建议,完善修复第三方登录“微信小程序”登录存在问题,同时优化state校验逻辑
This commit is contained in:
+4
-4
@@ -171,20 +171,20 @@ public interface SaBaseLoginUserApi {
|
||||
SaBaseClientLoginUser createClientUserWithEmail(String email);
|
||||
|
||||
/**
|
||||
* 使用账号和密码创建B端用户
|
||||
* 使用账号、密码和名称创建B端用户
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2026/6/25
|
||||
**/
|
||||
SaBaseLoginUser createUserWithAccount(String account, String password);
|
||||
SaBaseLoginUser createUserWithAccount(String account, String password, String name);
|
||||
|
||||
/**
|
||||
* 使用账号和密码创建C端用户
|
||||
* 使用账号、密码和名称创建C端用户
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2026/6/26
|
||||
**/
|
||||
SaBaseClientLoginUser createClientUserWithAccount(String account, String password);
|
||||
SaBaseClientLoginUser createClientUserWithAccount(String account, String password, String name);
|
||||
|
||||
/**
|
||||
* 执行注册
|
||||
|
||||
+21
-18
@@ -25,62 +25,65 @@ import vip.xiaonuo.common.exception.CommonException;
|
||||
public enum AuthPlatformEnum {
|
||||
|
||||
/** OAUTH */
|
||||
OAUTH("OAUTH"),
|
||||
OAUTH("OAUTH", "OAUTH"),
|
||||
|
||||
/** OIDC */
|
||||
OIDC("OIDC"),
|
||||
OIDC("OIDC", "OIDC"),
|
||||
|
||||
/** JWT */
|
||||
JWT("JWT"),
|
||||
JWT("JWT", "JWT"),
|
||||
|
||||
/** CAS */
|
||||
CAS("CAS"),
|
||||
CAS("CAS", "CAS"),
|
||||
|
||||
/** SAML */
|
||||
SAML("SAML"),
|
||||
SAML("SAML", "SAML"),
|
||||
|
||||
// =======以下为OIDC协议的具体实现======= //
|
||||
|
||||
/** IAM */
|
||||
IAM("IAM"),
|
||||
IAM("IAM", "IAM"),
|
||||
|
||||
/** 钉钉 */
|
||||
DINGTALK("DINGTALK"),
|
||||
DINGTALK("DINGTALK", "钉钉"),
|
||||
|
||||
/** 企业微信 */
|
||||
WORKWECHAT("WORKWECHAT"),
|
||||
WORKWECHAT("WORKWECHAT", "企业微信"),
|
||||
|
||||
/** 飞书 */
|
||||
FEISHU("FEISHU"),
|
||||
FEISHU("FEISHU", "飞书"),
|
||||
|
||||
/** WeLink */
|
||||
WELINK("WELINK"),
|
||||
WELINK("WELINK", "WeLink"),
|
||||
|
||||
/** 云之家 */
|
||||
YUNZHIJIA("YUNZHIJIA"),
|
||||
YUNZHIJIA("YUNZHIJIA", "云之家"),
|
||||
|
||||
/** QQ */
|
||||
QQ("QQ"),
|
||||
QQ("QQ", "QQ"),
|
||||
|
||||
/** 微信 */
|
||||
WECHAT("WECHAT"),
|
||||
WECHAT("WECHAT", "微信"),
|
||||
|
||||
/** 微信小程序 */
|
||||
WECHAT_MINI("WECHAT_MINI"),
|
||||
WECHAT_MINI("WECHAT_MINI", "微信小程序"),
|
||||
|
||||
/** 微博 */
|
||||
WEIBO("WEIBO"),
|
||||
WEIBO("WEIBO", "微博"),
|
||||
|
||||
/** 抖音 */
|
||||
DOUYIN("DOUYIN"),
|
||||
DOUYIN("DOUYIN", "抖音"),
|
||||
|
||||
/** 支付宝 */
|
||||
ALIPAY("ALIPAY");
|
||||
ALIPAY("ALIPAY", "支付宝");
|
||||
|
||||
private final String value;
|
||||
|
||||
AuthPlatformEnum(String value) {
|
||||
private final String description;
|
||||
|
||||
AuthPlatformEnum(String value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public static void validate(String value) {
|
||||
|
||||
+12
-4
@@ -101,11 +101,19 @@ public class AuthOauthClient extends AuthBaseClient<AuthOauthBaseJson> {
|
||||
throw new CommonException("code不能为空");
|
||||
}
|
||||
String state = request.getParam("state");
|
||||
if(ObjectUtil.isEmpty(state)) {
|
||||
throw new CommonException("state不能为空");
|
||||
}
|
||||
AuthRequest authRequest = new AuthOauthCommonClient(getAuthBaseJson()).getAuthRequest();
|
||||
AuthRequest authRequest = new AuthOauthCommonClient(getAuthBaseJson()).getAuthRequest(ObjectUtil.isEmpty(state));
|
||||
AuthResponse<AuthUser> authResponse = authRequest.login(AuthCallback.builder().code(code).state(state).build());
|
||||
|
||||
// 如果失败了,且是因为 state 校验失败(Illegal state),则尝试降级忽略 state 校验再次登录
|
||||
if(!authResponse.ok()) {
|
||||
String errorMsg = authResponse.getMsg();
|
||||
if(ObjectUtil.isNotEmpty(state) && errorMsg != null && errorMsg.contains("Illegal state")) {
|
||||
log.warn(">>> OAUTH state校验失败,尝试降级忽略state校验登录,state={}, error={}", state, errorMsg);
|
||||
authRequest = new AuthOauthCommonClient(getAuthBaseJson()).getAuthRequest(true);
|
||||
authResponse = authRequest.login(AuthCallback.builder().code(code).state(state).build());
|
||||
}
|
||||
}
|
||||
|
||||
if(!authResponse.ok()) {
|
||||
throw new CommonException(authResponse.getMsg());
|
||||
}
|
||||
|
||||
+5
@@ -29,6 +29,10 @@ import vip.xiaonuo.auth.core.protocol.oauth.AuthOauthBaseJson;
|
||||
public record AuthOauthCommonClient(AuthOauthBaseJson authOauthBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOauthBaseJson.getClientId();
|
||||
String clientSecret = authOauthBaseJson.getClientSecret();
|
||||
String callbackUrl = authOauthBaseJson.getCallbackUrl();
|
||||
@@ -37,6 +41,7 @@ public record AuthOauthCommonClient(AuthOauthBaseJson authOauthBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build(), authOauthBaseJson);
|
||||
}
|
||||
}
|
||||
|
||||
+29
-68
@@ -20,10 +20,8 @@ import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.exception.AuthException;
|
||||
import me.zhyd.oauth.model.AuthCallback;
|
||||
import me.zhyd.oauth.model.AuthResponse;
|
||||
import me.zhyd.oauth.model.AuthToken;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.utils.AuthStateUtils;
|
||||
@@ -98,23 +96,27 @@ public class AuthOidcClient extends AuthBaseClient<AuthOidcBaseJson> {
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String authPlatform = this.getAuthPlatform();
|
||||
AuthPlatformEnum authPlatformEnum = AuthPlatformEnum.valueOf(authPlatform);
|
||||
AuthRequest authRequest;
|
||||
switch (authPlatformEnum) {
|
||||
case IAM -> authRequest = new AuthOidcIamClient(getAuthBaseJson()).getAuthRequest();
|
||||
case QQ -> authRequest = new AuthOidcQqClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WECHAT -> authRequest = new AuthOidcWechatClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WECHAT_MINI -> authRequest = new AuthOidcWechatMiniClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WEIBO -> authRequest = new AuthOidcWeiboClient(getAuthBaseJson()).getAuthRequest();
|
||||
case DOUYIN -> authRequest = new AuthOidcDouyinClient(getAuthBaseJson()).getAuthRequest();
|
||||
case ALIPAY -> authRequest = new AuthOidcAlipayClient(getAuthBaseJson()).getAuthRequest();
|
||||
case DINGTALK -> authRequest = new AuthOidcDingTalkClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WORKWECHAT -> authRequest = new AuthOidcWorkWechatClient(getAuthBaseJson()).getAuthRequest();
|
||||
case FEISHU -> authRequest = new AuthOidcFeiShuClient(getAuthBaseJson()).getAuthRequest();
|
||||
case WELINK -> authRequest = new AuthOidcWeLinkClient(getAuthBaseJson()).getAuthRequest();
|
||||
case YUNZHIJIA -> authRequest = new AuthOidcYunZhiJiaClient(getAuthBaseJson()).getAuthRequest();
|
||||
default -> authRequest = new AuthOidcCommonClient(getAuthBaseJson()).getAuthRequest();
|
||||
case IAM -> authRequest = new AuthOidcIamClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case QQ -> authRequest = new AuthOidcQqClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case WECHAT -> authRequest = new AuthOidcWechatClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case WECHAT_MINI -> authRequest = new AuthOidcWechatMiniClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case WEIBO -> authRequest = new AuthOidcWeiboClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case DOUYIN -> authRequest = new AuthOidcDouyinClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case ALIPAY -> authRequest = new AuthOidcAlipayClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case DINGTALK -> authRequest = new AuthOidcDingTalkClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case WORKWECHAT -> authRequest = new AuthOidcWorkWechatClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case FEISHU -> authRequest = new AuthOidcFeiShuClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case WELINK -> authRequest = new AuthOidcWeLinkClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
case YUNZHIJIA -> authRequest = new AuthOidcYunZhiJiaClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
default -> authRequest = new AuthOidcCommonClient(getAuthBaseJson()).getAuthRequest(ignoreCheckState);
|
||||
}
|
||||
return authRequest;
|
||||
}
|
||||
@@ -143,63 +145,22 @@ public class AuthOidcClient extends AuthBaseClient<AuthOidcBaseJson> {
|
||||
throw new CommonException("code不能为空");
|
||||
}
|
||||
String state = request.getParam("state");
|
||||
if(ObjectUtil.isEmpty(state)) {
|
||||
throw new CommonException("state不能为空");
|
||||
}
|
||||
AuthRequest authRequest = this.getAuthRequest();
|
||||
AuthRequest authRequest = this.getAuthRequest(ObjectUtil.isEmpty(state));
|
||||
AuthResponse<AuthUser> authResponse = authRequest.login(AuthCallback.builder().code(code).state(state).build());
|
||||
|
||||
// 尝试正常登录流程(包含state校验)
|
||||
try {
|
||||
AuthResponse<AuthUser> authResponse = authRequest.login(AuthCallback.builder().code(code).state(state).build());
|
||||
|
||||
// 检查响应是否失败
|
||||
if(!authResponse.ok()) {
|
||||
String errorMsg = authResponse.getMsg();
|
||||
// 如果是state校验失败,尝试降级处理
|
||||
if(errorMsg != null && errorMsg.contains("Illegal state")) {
|
||||
log.warn(">>> OIDC state校验失败(响应失败),尝试跳过state校验直接获取token,state={}, error={}", state, errorMsg);
|
||||
return doLoginWithoutStateCheck(code);
|
||||
}
|
||||
throw new CommonException(errorMsg);
|
||||
// 如果失败了,且是因为 state 校验失败(Illegal state),则尝试降级忽略 state 校验再次登录
|
||||
if(!authResponse.ok()) {
|
||||
String errorMsg = authResponse.getMsg();
|
||||
if(ObjectUtil.isNotEmpty(state) && errorMsg != null && errorMsg.contains("Illegal state")) {
|
||||
log.warn(">>> OIDC state校验失败,尝试降级忽略state校验登录,state={}, error={}", state, errorMsg);
|
||||
authRequest = this.getAuthRequest(true);
|
||||
authResponse = authRequest.login(AuthCallback.builder().code(code).state(state).build());
|
||||
}
|
||||
|
||||
return handleAuthResponse(authResponse);
|
||||
} catch (AuthException e) {
|
||||
// 如果是异常形式的state校验失败
|
||||
if(e.getMessage() != null && e.getMessage().contains("Illegal state")) {
|
||||
log.warn(">>> OIDC state校验失败(异常),尝试跳过state校验直接获取token,state={}, error={}", state, e.getMessage());
|
||||
return doLoginWithoutStateCheck(code);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过state校验,直接用code换token和用户信息
|
||||
*/
|
||||
private AuthResponse<AuthUser> doLoginWithoutStateCheck(String code) {
|
||||
try {
|
||||
AuthRequest authRequest = this.getAuthRequest();
|
||||
// 直接用code换token(不校验state)
|
||||
AuthCallback authCallback = AuthCallback.builder()
|
||||
.code(code)
|
||||
.state("bypass-state-check") // 使用占位state
|
||||
.build();
|
||||
|
||||
// 获取token
|
||||
AuthToken authToken = authRequest.getAccessToken(authCallback);
|
||||
// 获取用户信息
|
||||
AuthUser authUser = authRequest.getUserInfo(authToken);
|
||||
|
||||
log.info(">>> OIDC跳过state校验成功获取用户信息,userId={}", authUser.getUuid());
|
||||
|
||||
return AuthResponse.<AuthUser>builder()
|
||||
.code(me.zhyd.oauth.enums.AuthResponseStatus.SUCCESS.getCode())
|
||||
.data(authUser)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.error(">>> OIDC跳过state校验后仍然失败", e);
|
||||
throw new CommonException("OIDC登录失败:{}", e.getMessage());
|
||||
if(!authResponse.ok()) {
|
||||
throw new CommonException(authResponse.getMsg());
|
||||
}
|
||||
return handleAuthResponse(authResponse);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -29,6 +29,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcCommonClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -37,6 +41,7 @@ public record AuthOidcCommonClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build(), authOidcBaseJson);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -30,6 +30,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcAlipayClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcAlipayClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build(), publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcDingTalkClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcDingTalkClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcDouyinClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcDouyinClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcFeiShuClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcFeiShuClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -33,6 +33,10 @@ import java.util.List;
|
||||
public record AuthOidcIamClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -43,6 +47,7 @@ public record AuthOidcIamClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientSecret(clientSecret)
|
||||
.scopes(scope)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build(), authOidcBaseJson);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcQqClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcQqClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcWechatClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcWechatClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -17,7 +17,6 @@ import com.xkcoding.http.support.hutool.HutoolImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.config.AuthConfig;
|
||||
import me.zhyd.oauth.request.AuthRequest;
|
||||
import me.zhyd.oauth.request.AuthWeChatOpenRequest;
|
||||
import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
|
||||
import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
|
||||
@@ -32,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcWechatMiniClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(true);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
HttpUtil.setHttp(new HutoolImpl());
|
||||
@@ -39,7 +42,7 @@ public record AuthOidcWechatMiniClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.ignoreCheckRedirectUri(true)
|
||||
.ignoreCheckState(true)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcWeiboClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -39,6 +43,7 @@ public record AuthOidcWeiboClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -30,6 +30,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcWeLinkClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -38,6 +42,7 @@ public record AuthOidcWeLinkClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcWorkWechatClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -41,6 +45,7 @@ public record AuthOidcWorkWechatClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.agentId(agentId)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -30,6 +30,10 @@ import vip.xiaonuo.auth.core.protocol.oidc.AuthOidcBaseJson;
|
||||
public record AuthOidcYunZhiJiaClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
|
||||
public AuthRequest getAuthRequest() {
|
||||
return getAuthRequest(false);
|
||||
}
|
||||
|
||||
public AuthRequest getAuthRequest(boolean ignoreCheckState) {
|
||||
String clientId = authOidcBaseJson.getClientId();
|
||||
String clientSecret = authOidcBaseJson.getClientSecret();
|
||||
String callbackUrl = authOidcBaseJson.getCallbackUrl();
|
||||
@@ -38,6 +42,7 @@ public record AuthOidcYunZhiJiaClient(AuthOidcBaseJson authOidcBaseJson) {
|
||||
.clientId(clientId)
|
||||
.clientSecret(clientSecret)
|
||||
.redirectUri(callbackUrl)
|
||||
.ignoreCheckState(ignoreCheckState)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,5 +30,5 @@ public interface AuthThirdUserService extends IService<AuthThirdUser> {
|
||||
* @author xuyuxiang
|
||||
* @date 2022/7/9 14:58
|
||||
*/
|
||||
void insertAuthThirdUser(String userId, AuthUser authUser);
|
||||
void insertAuthThirdUser(String userId, AuthUser authUser, String platform);
|
||||
}
|
||||
|
||||
+119
-148
@@ -21,6 +21,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.druid.util.StringUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -228,16 +229,20 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
// 校验登录端类型
|
||||
String clientType = authThirdRenderParam.getClientType();
|
||||
SaClientTypeEnum.validate(clientType);
|
||||
// 创建客户端
|
||||
AuthBaseClient<?> authSourceBaseClient = this.getAuthClient(platform);
|
||||
// 获取认证地址,需客户端类型
|
||||
String authorizeUrl = authSourceBaseClient.getAuthorizeUrl(clientType);
|
||||
// 构造结果
|
||||
AuthThirdRenderResult authThirdRenderResult = new AuthThirdRenderResult();
|
||||
// 设置授权地址
|
||||
authThirdRenderResult.setAuthorizeUrl(authorizeUrl);
|
||||
// 返回结果
|
||||
return authThirdRenderResult;
|
||||
try {
|
||||
// 创建客户端
|
||||
AuthBaseClient<?> authSourceBaseClient = this.getAuthClient(platform);
|
||||
// 获取认证地址,需客户端类型
|
||||
String authorizeUrl = authSourceBaseClient.getAuthorizeUrl(clientType);
|
||||
// 构造结果
|
||||
AuthThirdRenderResult authThirdRenderResult = new AuthThirdRenderResult();
|
||||
// 设置授权地址
|
||||
authThirdRenderResult.setAuthorizeUrl(authorizeUrl);
|
||||
// 返回结果
|
||||
return authThirdRenderResult;
|
||||
} catch (Exception e) {
|
||||
throw new CommonException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
@@ -251,39 +256,33 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
AuthBaseClient<?> authSourceBaseClient = this.getAuthClient(platform);
|
||||
// 获取state
|
||||
String state = SaHolder.getRequest().getParam(SaOAuth2Consts.Param.state);
|
||||
// 校验state
|
||||
if(ObjectUtil.isEmpty(state)) {
|
||||
state = SaHolder.getRequest().getParam("RelayState");
|
||||
if(ObjectUtil.isEmpty(state)) {
|
||||
throw new CommonException("state不能为空");
|
||||
}
|
||||
}
|
||||
// 获取缓存操作类
|
||||
CommonCacheOperator commonCacheOperator = SpringUtil.getBean(CommonCacheOperator.class);
|
||||
// 获取缓存值
|
||||
Object stateCacheValueObj = null;
|
||||
try {
|
||||
// 对state进行安全处理,防止特殊字符导致Redis异常
|
||||
if (state.length() > 500) {
|
||||
log.warn(">>> SSO state 过长({}字符),跳过Redis校验 state={}", state.length(), state.substring(0, 50) + "...");
|
||||
} else {
|
||||
stateCacheValueObj = commonCacheOperator.get(CONFIG_CACHE_KEY + state);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(">>> SSO state Redis查询异常,跳过校验 state={}, error={}", state, e.getMessage());
|
||||
}
|
||||
// 默认登录端类型
|
||||
String clientType = SaClientTypeEnum.B.getValue();
|
||||
// 判断是否为空
|
||||
if(ObjectUtil.isNotEmpty(stateCacheValueObj)){
|
||||
// 转换为json对象
|
||||
JSONObject stateCacheValueJsonObject = JSONUtil.parseObj(stateCacheValueObj);
|
||||
// 获取登录端类型
|
||||
clientType = stateCacheValueJsonObject.getStr("clientType");
|
||||
// 移除缓存
|
||||
commonCacheOperator.remove(CONFIG_CACHE_KEY + state);
|
||||
} else {
|
||||
log.warn(">>> SSO state 校验失败(可能IdP未原样返回或门户发起登录),跳过校验 state={}", state);
|
||||
// 如果state不为空,尝试从缓存中获取clientType
|
||||
if(ObjectUtil.isNotEmpty(state)) {
|
||||
// 获取缓存操作类
|
||||
CommonCacheOperator commonCacheOperator = SpringUtil.getBean(CommonCacheOperator.class);
|
||||
// 获取缓存值
|
||||
Object stateCacheValueObj = null;
|
||||
try {
|
||||
stateCacheValueObj = commonCacheOperator.get(CONFIG_CACHE_KEY + state);
|
||||
} catch (Exception e) {
|
||||
log.warn(">>> SSO state Redis查询异常,跳过校验 state={}, error={}", state, e.getMessage());
|
||||
}
|
||||
// 判断是否为空
|
||||
if(ObjectUtil.isNotEmpty(stateCacheValueObj)){
|
||||
// 转换为json对象
|
||||
JSONObject stateCacheValueJsonObject = JSONUtil.parseObj(stateCacheValueObj);
|
||||
// 获取登录端类型
|
||||
clientType = stateCacheValueJsonObject.getStr("clientType");
|
||||
// 移除缓存
|
||||
commonCacheOperator.remove(CONFIG_CACHE_KEY + state);
|
||||
} else {
|
||||
log.warn(">>> SSO state 校验失败(可能未使用render发起登录),跳过校验 state={}", state);
|
||||
}
|
||||
}
|
||||
// 执行请求
|
||||
AuthResponse<AuthUser> authResponse = authSourceBaseClient.doLogin();
|
||||
@@ -292,26 +291,27 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
AuthUser authUser = authResponse.getData();
|
||||
// 获取第三方用户id
|
||||
String uuid = authUser.getUuid();
|
||||
// 获取第三方用户来源
|
||||
String source = authUser.getSource();
|
||||
// 根据第三方用户id和用户来源获取用户信息
|
||||
// 根据第三方用户id和平台标识获取用户信息
|
||||
AuthThirdUser authThirdUser = this.getOne(new LambdaQueryWrapper<AuthThirdUser>().eq(AuthThirdUser::getThirdId, uuid)
|
||||
.eq(AuthThirdUser::getCategory, source));
|
||||
.eq(AuthThirdUser::getCategory, platform));
|
||||
// 定义系统用户id
|
||||
String userId;
|
||||
if(ObjectUtil.isEmpty(authThirdUser)) {
|
||||
// 如果三方用户不存在,自动创建本地用户并绑定
|
||||
userId = this.createAndBindUser(authUser, clientType);
|
||||
userId = this.createAndBindUser(authUser, platform, clientType);
|
||||
} else {
|
||||
// 否则直接获取用户id,判断是否存在(有可能没绑定)
|
||||
userId = authThirdUser.getUserId();
|
||||
if(ObjectUtil.isEmpty(userId)) {
|
||||
// 三方用户存在但未绑定本地用户,自动创建并绑定
|
||||
userId = this.createAndBindUserForExistThird(authUser, authThirdUser, clientType);
|
||||
userId = this.createAndBindUserForExistThird(authUser, authThirdUser, platform, clientType);
|
||||
}
|
||||
}
|
||||
// 登录设备
|
||||
String device = platform.equalsIgnoreCase(AuthPlatformEnum.WECHAT_MINI.getValue())?
|
||||
AuthDeviceTypeEnum.MINI.getValue():AuthDeviceTypeEnum.PC.getValue();
|
||||
// 已绑定用户,直接用userId登录
|
||||
return authService.doLoginById(userId, AuthDeviceTypeEnum.PC.getValue(), clientType);
|
||||
return authService.doLoginById(userId, device, clientType);
|
||||
} else {
|
||||
throw new CommonException("第三方登录授权回调失败,原因:{}", authResponse.getMsg());
|
||||
}
|
||||
@@ -359,26 +359,6 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
return this.page(CommonPageRequest.defaultPage(), queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存三方用户并返回主键
|
||||
*
|
||||
* @author xuyuxiang
|
||||
* @date 2022/7/9 14:58
|
||||
*/
|
||||
private String insertAuthThirdUser(AuthUser authUser) {
|
||||
AuthThirdUser authThirdUser = new AuthThirdUser();
|
||||
authThirdUser.setThirdId(authUser.getUuid());
|
||||
authThirdUser.setUserId(null);
|
||||
authThirdUser.setAvatar(authUser.getAvatar());
|
||||
authThirdUser.setName(authUser.getUsername());
|
||||
authThirdUser.setNickname(authUser.getNickname());
|
||||
authThirdUser.setGender(ObjectUtil.isNotEmpty(authUser.getGender())?authUser.getGender().getDesc():"");
|
||||
authThirdUser.setCategory(authUser.getSource());
|
||||
authThirdUser.setExtJson(JSONUtil.toJsonStr(authUser.getRawUserInfo()));
|
||||
this.save(authThirdUser);
|
||||
return authThirdUser.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建授权请求客户端
|
||||
*
|
||||
@@ -665,53 +645,16 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
* 创建本地用户并绑定三方用户(三方用户记录不存在的情况)
|
||||
*
|
||||
* @param authUser 第三方用户信息
|
||||
* @param platform 平台标识
|
||||
* @param clientType 登录端类型
|
||||
* @return 创建的本地用户ID
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2025/06/26
|
||||
*/
|
||||
private String createAndBindUser(AuthUser authUser, String clientType) {
|
||||
// 从第三方用户信息中提取字段
|
||||
String username = authUser.getUsername();
|
||||
String email = authUser.getEmail();
|
||||
String phone = authUser.getSource().equalsIgnoreCase("phone") ? authUser.getUsername() : null;
|
||||
|
||||
// 定义本地用户
|
||||
String userId;
|
||||
|
||||
// 根据登录端类型创建用户
|
||||
if(SaClientTypeEnum.B.getValue().equals(clientType)) {
|
||||
// B端用户创建逻辑
|
||||
if(StrUtil.isNotBlank(phone)) {
|
||||
userId = loginUserApi.createUserWithPhone(phone).getId();
|
||||
} else if(StrUtil.isNotBlank(email)) {
|
||||
userId = loginUserApi.createUserWithEmail(email).getId();
|
||||
} else if(StrUtil.isNotBlank(username)) {
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = loginUserApi.createUserWithAccount(username, randomPassword).getId();
|
||||
} else {
|
||||
String uuid = authUser.getUuid();
|
||||
String account = AuthAccountPrefixEnum.SSO.getValue() + (uuid.length() >= 8 ? uuid.substring(0, 8) : uuid);
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = loginUserApi.createUserWithAccount(account, randomPassword).getId();
|
||||
}
|
||||
} else {
|
||||
// C端用户创建逻辑
|
||||
if(StrUtil.isNotBlank(phone)) {
|
||||
userId = clientLoginUserApi.createClientUserWithPhone(phone).getId();
|
||||
} else if(StrUtil.isNotBlank(email)) {
|
||||
userId = clientLoginUserApi.createClientUserWithEmail(email).getId();
|
||||
} else if(StrUtil.isNotBlank(username)) {
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = clientLoginUserApi.createClientUserWithAccount(username, randomPassword).getId();
|
||||
} else {
|
||||
String uuid = authUser.getUuid();
|
||||
String account = AuthAccountPrefixEnum.SSO.getValue() + (uuid.length() >= 8 ? uuid.substring(0, 8) : uuid);
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = clientLoginUserApi.createClientUserWithAccount(account, randomPassword).getId();
|
||||
}
|
||||
}
|
||||
private String createAndBindUser(AuthUser authUser, String platform, String clientType) {
|
||||
// 自动创建本地用户
|
||||
String userId = this.autoCreateUser(authUser, platform, clientType);
|
||||
|
||||
// 插入三方用户记录并绑定
|
||||
AuthThirdUser authThirdUser = new AuthThirdUser();
|
||||
@@ -721,11 +664,11 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
authThirdUser.setName(authUser.getUsername());
|
||||
authThirdUser.setNickname(authUser.getNickname());
|
||||
authThirdUser.setGender(authUser.getGender() != null ? authUser.getGender().getDesc() : "未知");
|
||||
authThirdUser.setCategory(authUser.getSource());
|
||||
authThirdUser.setCategory(platform);
|
||||
authThirdUser.setExtJson(JSONUtil.toJsonStr(authUser.getRawUserInfo()));
|
||||
this.save(authThirdUser);
|
||||
|
||||
log.info(">>> SSO登录自动创建用户成功,userId={}, thirdId={}, source={}", userId, authUser.getUuid(), authUser.getSource());
|
||||
log.info(">>> SSO登录自动创建用户成功,userId={}, thirdId={}, source={}", userId, authUser.getUuid(), platform);
|
||||
|
||||
return userId;
|
||||
}
|
||||
@@ -735,58 +678,86 @@ public class AuthThirdServiceImpl extends ServiceImpl<AuthThirdMapper, AuthThird
|
||||
*
|
||||
* @param authUser 第三方用户信息
|
||||
* @param authThirdUser 已存在的三方用户记录
|
||||
* @param platform 平台标识
|
||||
* @param clientType 登录端类型
|
||||
* @return 创建的本地用户ID
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2025/06/26
|
||||
*/
|
||||
private String createAndBindUserForExistThird(AuthUser authUser, AuthThirdUser authThirdUser, String clientType) {
|
||||
// 从第三方用户信息中提取字段
|
||||
String username = authUser.getUsername();
|
||||
String email = authUser.getEmail();
|
||||
String phone = authUser.getSource().equalsIgnoreCase("phone") ? authUser.getUsername() : null;
|
||||
|
||||
// 定义本地用户
|
||||
String userId;
|
||||
|
||||
// 根据登录端类型创建用户
|
||||
if(SaClientTypeEnum.B.getValue().equals(clientType)) {
|
||||
// B端用户创建逻辑
|
||||
if(StrUtil.isNotBlank(phone)) {
|
||||
userId = loginUserApi.createUserWithPhone(phone).getId();
|
||||
} else if(StrUtil.isNotBlank(email)) {
|
||||
userId = loginUserApi.createUserWithEmail(email).getId();
|
||||
} else if(StrUtil.isNotBlank(username)) {
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = loginUserApi.createUserWithAccount(username, randomPassword).getId();
|
||||
} else {
|
||||
String account = AuthAccountPrefixEnum.SSO.getValue() + (authUser.getUuid().length() >= 8 ? authUser.getUuid().substring(0, 8) : authUser.getUuid());
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = loginUserApi.createUserWithAccount(account, randomPassword).getId();
|
||||
}
|
||||
} else {
|
||||
// C端用户创建逻辑
|
||||
if(StrUtil.isNotBlank(phone)) {
|
||||
userId = clientLoginUserApi.createClientUserWithPhone(phone).getId();
|
||||
} else if(StrUtil.isNotBlank(email)) {
|
||||
userId = clientLoginUserApi.createClientUserWithEmail(email).getId();
|
||||
} else if(StrUtil.isNotBlank(username)) {
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = clientLoginUserApi.createClientUserWithAccount(username, randomPassword).getId();
|
||||
} else {
|
||||
String account = AuthAccountPrefixEnum.SSO.getValue() + (authUser.getUuid().length() >= 8 ? authUser.getUuid().substring(0, 8) : authUser.getUuid());
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = clientLoginUserApi.createClientUserWithAccount(account, randomPassword).getId();
|
||||
}
|
||||
}
|
||||
private String createAndBindUserForExistThird(AuthUser authUser, AuthThirdUser authThirdUser, String platform, String clientType) {
|
||||
// 自动创建本地用户
|
||||
String userId = this.autoCreateUser(authUser, platform, clientType);
|
||||
|
||||
// 更新三方用户记录,绑定userId
|
||||
authThirdUser.setUserId(userId);
|
||||
this.updateById(authThirdUser);
|
||||
|
||||
log.info(">>> SSO登录为已存在三方用户创建本地用户并绑定成功,userId={}, thirdId={}, source={}", userId, authUser.getUuid(), authUser.getSource());
|
||||
log.info(">>> SSO登录为已存在三方用户创建本地用户并绑定成功,userId={}, thirdId={}, source={}", userId, authUser.getUuid(), platform);
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动创建本地用户
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/07/05
|
||||
*/
|
||||
private String autoCreateUser(AuthUser authUser, String platform, String clientType) {
|
||||
String email = authUser.getEmail();
|
||||
String phone = platform.equalsIgnoreCase("phone") ? authUser.getUsername() : null;
|
||||
String userId;
|
||||
|
||||
// 生成账号:来源 + "_" + 完整UUID,保证全局唯一性,避免截取导致的冲突
|
||||
String account = platform.toLowerCase() + "_" + authUser.getUuid();
|
||||
|
||||
// 生成美观的默认名称(昵称)
|
||||
String name = authUser.getNickname();
|
||||
if (StrUtil.isBlank(name)) {
|
||||
name = authUser.getUsername();
|
||||
}
|
||||
if (StrUtil.isBlank(name)) {
|
||||
name = getFriendlyPlatformName(platform) + "用户_" + RandomUtil.randomString(10);
|
||||
}
|
||||
|
||||
if (SaClientTypeEnum.B.getValue().equals(clientType)) {
|
||||
if (StrUtil.isNotBlank(phone)) {
|
||||
userId = loginUserApi.createUserWithPhone(phone).getId();
|
||||
} else if (StrUtil.isNotBlank(email)) {
|
||||
userId = loginUserApi.createUserWithEmail(email).getId();
|
||||
} else {
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = loginUserApi.createUserWithAccount(account, randomPassword, name).getId();
|
||||
}
|
||||
} else {
|
||||
if (StrUtil.isNotBlank(phone)) {
|
||||
userId = clientLoginUserApi.createClientUserWithPhone(phone).getId();
|
||||
} else if (StrUtil.isNotBlank(email)) {
|
||||
userId = clientLoginUserApi.createClientUserWithEmail(email).getId();
|
||||
} else {
|
||||
String randomPassword = RandomUtil.randomString(16);
|
||||
userId = clientLoginUserApi.createClientUserWithAccount(account, randomPassword, name).getId();
|
||||
}
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取友好的平台名称
|
||||
*
|
||||
* @author yubaoshan
|
||||
* @date 2024/07/05
|
||||
*/
|
||||
private String getFriendlyPlatformName(String source) {
|
||||
if (StrUtil.isBlank(source)) {
|
||||
return "第三方";
|
||||
}
|
||||
for (AuthPlatformEnum platformEnum : AuthPlatformEnum.values()) {
|
||||
if (platformEnum.getValue().equalsIgnoreCase(source)) {
|
||||
return platformEnum.getDescription();
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ import vip.xiaonuo.auth.modular.third.service.AuthThirdUserService;
|
||||
public class AuthThirdUserServiceImpl extends ServiceImpl<AuthThirdUserMapper, AuthThirdUser> implements AuthThirdUserService {
|
||||
|
||||
@Override
|
||||
public void insertAuthThirdUser(String userId, AuthUser authUser) {
|
||||
public void insertAuthThirdUser(String userId, AuthUser authUser, String platform) {
|
||||
AuthThirdUser authThirdUser = new AuthThirdUser();
|
||||
authThirdUser.setThirdId(authUser.getUuid());
|
||||
authThirdUser.setUserId(userId);
|
||||
@@ -39,7 +39,7 @@ public class AuthThirdUserServiceImpl extends ServiceImpl<AuthThirdUserMapper, A
|
||||
authThirdUser.setName(authUser.getUsername());
|
||||
authThirdUser.setNickname(authUser.getNickname());
|
||||
authThirdUser.setGender(ObjectUtil.isEmpty(authUser.getGender()) ? null : authUser.getGender().getDesc());
|
||||
authThirdUser.setCategory(authUser.getSource());
|
||||
authThirdUser.setCategory(platform);
|
||||
authThirdUser.setExtJson(JSONUtil.toJsonStr(authUser.getRawUserInfo()));
|
||||
this.save(authThirdUser);
|
||||
}
|
||||
|
||||
+3
-3
@@ -210,14 +210,14 @@ public class ClientLoginUserApiProvider implements SaBaseLoginUserApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaBaseLoginUser createUserWithAccount(String account, String password) {
|
||||
public SaBaseLoginUser createUserWithAccount(String account, String password, String name) {
|
||||
// C端用户API不实现B端用户创建
|
||||
throw new UnsupportedOperationException("C端用户API不支持创建B端用户");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaBaseClientLoginUser createClientUserWithAccount(String account, String password) {
|
||||
ClientUser clientUser = clientUserService.createUserWithAccount(account, password);
|
||||
public SaBaseClientLoginUser createClientUserWithAccount(String account, String password, String name) {
|
||||
ClientUser clientUser = clientUserService.createUserWithAccount(account, password, name);
|
||||
return BeanUtil.copyProperties(clientUser, ClientLoginUser.class);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -312,12 +312,12 @@ public interface ClientUserService extends IService<ClientUser> {
|
||||
ClientUser createUserWithEmail(String email);
|
||||
|
||||
/**
|
||||
* 根据账号密码创建用户
|
||||
* 根据账号密码和名称创建用户
|
||||
*
|
||||
* @author xuyuxiang
|
||||
* @date 2022/8/25 15:16
|
||||
**/
|
||||
ClientUser createUserWithAccount(String account, String password);
|
||||
ClientUser createUserWithAccount(String account, String password, String name);
|
||||
|
||||
/**
|
||||
* 判断当前用户密码是否过期
|
||||
|
||||
+3
-3
@@ -1041,10 +1041,10 @@ public class ClientUserServiceImpl extends ServiceImpl<ClientUserMapper, ClientU
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public ClientUser createUserWithAccount(String account, String password) {
|
||||
public ClientUser createUserWithAccount(String account, String password, String name) {
|
||||
ClientUserAddParam clientUserAddParam = new ClientUserAddParam();
|
||||
clientUserAddParam.setAccount(account);
|
||||
clientUserAddParam.setName(account);
|
||||
clientUserAddParam.setName(StrUtil.isBlank(name) ? account : name);
|
||||
clientUserAddParam.setPassword(password);
|
||||
clientUserAddParam.setGender(CommonGenderEnum.UNKNOWN.getValue());
|
||||
// 保存用户
|
||||
@@ -1151,7 +1151,7 @@ public class ClientUserServiceImpl extends ServiceImpl<ClientUserMapper, ClientU
|
||||
// 校验密码
|
||||
ClientPasswordUtl.validNewPassword(password);
|
||||
// 根据账号密码创建用户
|
||||
this.createUserWithAccount(account, password);
|
||||
this.createUserWithAccount(account, password, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -216,13 +216,13 @@ public class SysLoginUserApiProvider implements SaBaseLoginUserApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaBaseLoginUser createUserWithAccount(String account, String password) {
|
||||
SysUser sysUser = sysUserService.createUserWithAccount(account, password);
|
||||
public SaBaseLoginUser createUserWithAccount(String account, String password, String name) {
|
||||
SysUser sysUser = sysUserService.createUserWithAccount(account, password, name);
|
||||
return BeanUtil.copyProperties(sysUser, SysLoginUser.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaBaseClientLoginUser createClientUserWithAccount(String account, String password) {
|
||||
public SaBaseClientLoginUser createClientUserWithAccount(String account, String password, String name) {
|
||||
// B端用户API不实现C端用户创建
|
||||
throw new UnsupportedOperationException("B端用户API不支持创建C端用户");
|
||||
}
|
||||
|
||||
+2
-2
@@ -602,12 +602,12 @@ public interface SysUserService extends IService<SysUser> {
|
||||
SysUser createUserWithEmail(String email);
|
||||
|
||||
/**
|
||||
* 根据账号密码创建用户
|
||||
* 根据账号密码和名称创建用户
|
||||
*
|
||||
* @author xuyuxiang
|
||||
* @date 2022/8/25 15:16
|
||||
**/
|
||||
SysUser createUserWithAccount(String account, String password);
|
||||
SysUser createUserWithAccount(String account, String password, String name);
|
||||
|
||||
/**
|
||||
* 判断当前用户是否需要绑定手机号
|
||||
|
||||
+3
-3
@@ -2295,10 +2295,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public SysUser createUserWithAccount(String account, String password) {
|
||||
public SysUser createUserWithAccount(String account, String password, String name) {
|
||||
SysUserAddParam sysUserAddParam = new SysUserAddParam();
|
||||
sysUserAddParam.setAccount(account);
|
||||
sysUserAddParam.setName(account);
|
||||
sysUserAddParam.setName(StrUtil.isBlank(name) ? account : name);
|
||||
sysUserAddParam.setPassword(password);
|
||||
sysUserAddParam.setOrgId(this.getDefaultNewUserOrgId());
|
||||
sysUserAddParam.setPositionId(this.getDefaultNewUserPositionId());
|
||||
@@ -2458,7 +2458,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
// 校验密码
|
||||
SysPasswordUtil.validNewPassword(password);
|
||||
// 根据账号密码创建用户
|
||||
this.createUserWithAccount(account, password);
|
||||
this.createUserWithAccount(account, password, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -603,8 +603,23 @@ INSERT INTO `DEV_DICT` VALUES ('1560342111344234497', '0', '定时任务状态',
|
||||
INSERT INTO `DEV_DICT` VALUES ('1560342186812346370', '1560342111344234497', '运行', 'RUNNING', 'pink', 'DHhBaibuBk', 'FRM', 20, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1560342250096005121', '1560342111344234497', '停止', 'STOPPED', 'red', 'O6KfK7Cobx', 'FRM', 20, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595062998102017', '0', '三方用户分类', 'THIRD_CATEGORY', 'default', 'OqMe62ViBY', 'FRM', 18, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860545', '1561595062998102017', '山信通IAM', 'IAM', 'pink', 'lZq8s2ehA5', 'FRM', 10, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595322336112641', '1561595062998102017', '微信WECHAT', 'WECHAT_OPEN', 'red', 'pGhKCHQ7hF', 'FRM', 20, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860545', '1561595062998102017', 'OAUTH', 'OAUTH', 'pink', 'lZq8s2ehA5', 'FRM', 10, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860546', '1561595062998102017', 'OIDC', 'OIDC', 'red', 'pGhKCHQ7hF', 'FRM', 20, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860547', '1561595062998102017', 'JWT', 'JWT', 'orange', 'KDLmGWwMkJ', 'FRM', 30, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860548', '1561595062998102017', 'CAS', 'CAS', 'green', 'JMkb4b45Xd', 'FRM', 40, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860549', '1561595062998102017', 'SAML', 'SAML', 'cyan', 'Vewyfq4W15', 'FRM', 50, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860550', '1561595062998102017', 'IAM', 'IAM', 'blue', 'NqMe62ViBY', 'FRM', 60, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860551', '1561595062998102017', '钉钉', 'DINGTALK', 'purple', 'PqMe62ViBY', 'FRM', 70, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860552', '1561595062998102017', '企业微信', 'WORKWECHAT', 'gold', 'QqMe62ViBY', 'FRM', 80, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860553', '1561595062998102017', '飞书', 'FEISHU', 'pink', 'RqMe62ViBY', 'FRM', 90, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860554', '1561595062998102017', 'WeLink', 'WELINK', 'red', 'SqMe62ViBY', 'FRM', 100, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860555', '1561595062998102017', '云之家', 'YUNZHIJIA', 'orange', 'TqMe62ViBY', 'FRM', 110, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860556', '1561595062998102017', 'QQ', 'QQ', 'green', 'UqMe62ViBY', 'FRM', 120, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860557', '1561595062998102017', '微信', 'WECHAT', 'cyan', 'VqMe62ViBY', 'FRM', 130, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860558', '1561595062998102017', '微信小程序', 'WECHAT_MINI', 'blue', 'WqMe62ViBY', 'FRM', 140, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860559', '1561595062998102017', '微博', 'WEIBO', 'purple', 'XqMe62ViBY', 'FRM', 150, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860560', '1561595062998102017', '抖音', 'DOUYIN', 'gold', 'YqMe62ViBY', 'FRM', 160, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1561595252714860561', '1561595062998102017', '支付宝', 'ALIPAY', 'pink', 'ZqMe62ViBY', 'FRM', 170, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1567580351742619650', '0', '系统消息类型', 'MESSAGE_CATEGORY', 'default', 'UPIN4KJqvT', 'FRM', 19, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1567580424270524418', '1567580351742619650', '系统', 'SYS', 'pink', 'l7Mc5zE5ib', 'FRM', 10, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
INSERT INTO `DEV_DICT` VALUES ('1567580487684206594', '1567580351742619650', '业务', 'BIZ', 'red', 'nYhpV3ep7j', 'FRM', 20, NULL, 'NOT_DELETE', NULL, NULL, NULL, NULL);
|
||||
|
||||
Reference in New Issue
Block a user