⚡ 小程序密码/短信登录按 User-Type=mp 走 blade_mp_user

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-12 14:22:33 +08:00
parent d8b10377f0
commit c3edca04a5
2 changed files with 38 additions and 34 deletions
@@ -88,7 +88,8 @@ public class Oauth2SmsEndpoint {
return R.fail(USER_PHONE_NOT_FOUND);
}
// 校验手机是否已注册,防止恶意发送验证码
OAuth2Request request = OAuth2Request.create();
// buildArgs:带上 User-Type 等请求头,小程序传 User-Type=mp 时查 blade_mp_user
OAuth2Request request = OAuth2Request.create().buildArgs();
request.setTenantId(tenantId);
OAuth2User oAuth2User = userService.loadByPhone(decryptedPhone, request);
if (oAuth2User == null) {
@@ -53,13 +53,8 @@ public class BladeUserDetailService implements OAuth2UserService {
@Override
public OAuth2User loadByUserId(String userId, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
// 小程序刷新/鉴权:直接查 blade_mp_user
if (MpUserIdentity.DETAIL_TYPE.equalsIgnoreCase(userType)) {
// 小程序刷新/鉴权:User-Type=mp 时只查 blade_mp_user
if (isMpLoginRequest(request)) {
OAuth2User mpUser = loadMpUserById(userId);
if (mpUser == null) {
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
@@ -67,14 +62,14 @@ public class BladeUserDetailService implements OAuth2UserService {
return mpUser;
}
// 系统用户
String userType = resolveUserType(request);
R<UserInfo> result = userClient.userInfo(Func.toLong(userId), userType);
if (result != null && result.isSuccess() && result.getData() != null
&& result.getData().getUser() != null) {
return TokenUtil.convertUser(result.getData(), request);
}
// 兼容:未带 userType=mp 时,回落查询小程序用户(令牌刷新)
// 兼容:刷新令牌未带 User-Type=mp 时,回落查询小程序用户
OAuth2User mpUser = loadMpUserById(userId);
if (mpUser != null) {
return mpUser;
@@ -85,14 +80,10 @@ public class BladeUserDetailService implements OAuth2UserService {
@Override
public OAuth2User loadByUsername(String username, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
String tenantId = request.getTenantId();
// 小程序用户:按账号查 blade_mp_user
if (MpUserIdentity.DETAIL_TYPE.equalsIgnoreCase(userType)) {
// 小程序账号密码 / 图形验证码登录:仅查 blade_mp_user
if (isMpLoginRequest(request)) {
R<MpUserInfo> mpResult = mpUserClient.userInfoByAccount(tenantId, username);
if (mpResult == null || !mpResult.isSuccess() || mpResult.getData() == null) {
return null;
@@ -100,43 +91,55 @@ public class BladeUserDetailService implements OAuth2UserService {
return TokenUtil.convertMpUser(mpResult.getData());
}
// 获取用户信息
String userType = resolveUserType(request);
R<UserInfo> result = userClient.userInfo(tenantId, username, userType);
if (!result.isSuccess()) {
if (result == null || !result.isSuccess()) {
return null;
}
// 构建oauth2用户信息
return TokenUtil.convertUser(result.getData(), request);
}
@Override
public OAuth2User loadByPhone(String phone, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
String tenantId = request.getTenantId();
// 小程序用户类型:仅查 blade_mp_user
if (MpUserIdentity.DETAIL_TYPE.equalsIgnoreCase(userType)) {
// 小程序短信登录:仅查 blade_mp_user
if (isMpLoginRequest(request)) {
return loadMpUserByPhone(tenantId, phone);
}
// 获取用户信息
String userType = resolveUserType(request);
R<UserInfo> result = userClient.userInfoByPhone(tenantId, phone, userType);
if (!result.isSuccess()) {
return null;
if (result != null && result.isSuccess() && result.getData() != null) {
return TokenUtil.convertUser(result.getData(), request);
}
// 构建oauth2用户信息
return TokenUtil.convertUser(result.getData(), request);
// 发短信校验等未带 User-Type 时,回落小程序用户,避免 mp 账号收不到验证码
return loadMpUserByPhone(tenantId, phone);
}
@Override
public boolean validateUser(OAuth2User user) {
return Optional.ofNullable(user)
.filter(u -> u.getUserId() != null && !u.getUserId().isEmpty()) // 检查userId不为空
.filter(u -> u.getAuthorities() != null && !u.getAuthorities().isEmpty()) // 检查authorities不为空
.isPresent(); // 如果上述条件都满足,则返回true,否则返回false
.filter(u -> u.getUserId() != null && !u.getUserId().isEmpty())
.filter(u -> u.getAuthorities() != null && !u.getAuthorities().isEmpty())
.isPresent();
}
/**
* 是否小程序登录:请求头 User-Type=mp(Web 与小程序共用 saber3 客户端,不能按 clientId 分流)
*/
private boolean isMpLoginRequest(OAuth2Request request) {
return request != null && isMpUserType(request.getUserType());
}
private boolean isMpUserType(String userType) {
return MpUserIdentity.DETAIL_TYPE.equalsIgnoreCase(Func.toStr(userType));
}
private String resolveUserType(OAuth2Request request) {
return Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
}
private OAuth2User loadMpUserById(String userId) {
@@ -150,7 +153,7 @@ public class BladeUserDetailService implements OAuth2UserService {
return TokenUtil.convertMpUser(result.getData());
}
} catch (Exception exception) {
// 非小程序用户场景忽略,继续走系统用户
// 非小程序用户场景忽略
}
return null;
}