♻️ 微信与短信登录改走MpLoginSupport自动建号建档

This commit is contained in:
2026-10-23 15:58:42 +08:00
parent a8e059e92e
commit 924134226f
2 changed files with 28 additions and 30 deletions
@@ -27,6 +27,7 @@ package org.springblade.auth.granter;
import jakarta.servlet.http.HttpServletRequest;
import org.springblade.auth.constant.BladeAuthConstant;
import org.springblade.auth.service.MpLoginSupport;
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
@@ -43,10 +44,15 @@ import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.resource.feign.ISmsClient;
import org.springblade.system.pojo.enums.MpUserIdentity;
import org.springframework.stereotype.Component;
/**
* SmsTokenGranter
* <p>
* 除验证码校验外,还要按请求来源分流:小程序(User-Type: mp)登录时账号不存在要自动建,
* Web 短信登录保持原样不建号。建号逻辑不能下沉到 {@code BladeUserDetailService.loadByPhone},
* 那条方法还被「发送短信验证码」复用,会在发码时就建出账号(刷号)。
*
* @author BladeX
*/
@@ -56,12 +62,14 @@ public class SmsTokenGranter extends AbstractTokenGranter {
private final OAuth2UserService userService;
private final ISmsClient smsClient;
private final OAuth2Properties properties;
private final MpLoginSupport mpLoginSupport;
public SmsTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, ISmsClient smsClient, OAuth2Properties properties) {
public SmsTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, ISmsClient smsClient, OAuth2Properties properties, MpLoginSupport mpLoginSupport) {
super(clientService, userService, passwordHandler);
this.userService = userService;
this.smsClient = smsClient;
this.properties = properties;
this.mpLoginSupport = mpLoginSupport;
}
@Override
@@ -86,8 +94,10 @@ public class SmsTokenGranter extends AbstractTokenGranter {
if (!result.isSuccess()) {
throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
}
// 获取用户信息
OAuth2User user = userService.loadByPhone(decryptedPhone, request);
// 获取用户信息:只有小程序登录才允许自动建号,Web 短信登录仍走原查询
OAuth2User user = isMpLoginRequest(request)
? mpLoginSupport.ensureLoginAccount(tenantId, decryptedPhone, null)
: userService.loadByPhone(decryptedPhone, request);
// 校验用户信息
if (!userService.validateUser(user)) {
throw new UserInvalidException(OAuth2TokenConstant.TOKEN_NOT_CORRECT);
@@ -97,6 +107,13 @@ public class SmsTokenGranter extends AbstractTokenGranter {
return user;
}
/**
* 是否小程序登录:请求头 User-Type=mp(Web 与小程序共用客户端,不能按 clientId 分流)
*/
private boolean isMpLoginRequest(OAuth2Request request) {
return request != null && MpUserIdentity.DETAIL_TYPE.equalsIgnoreCase(Func.toStr(request.getUserType()));
}
private SmsCode buildSmsCode() {
HttpServletRequest request = WebUtil.getRequest();
return new SmsCode().setId(request.getParameter("id"))
@@ -2,7 +2,7 @@ package org.springblade.auth.granter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.auth.service.MpLoginSupport;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
@@ -11,12 +11,9 @@ import org.springblade.core.oauth2.service.OAuth2Client;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.system.feign.IMpUserClient;
import org.springblade.system.pojo.entity.MpUserInfo;
import org.springblade.thirdparty.wechat.constant.WechatMiniConstant;
import org.springblade.thirdparty.wechat.exception.WechatMiniException;
import org.springblade.thirdparty.wechat.pojo.vo.WechatPhoneVO;
@@ -28,8 +25,8 @@ import org.springframework.stereotype.Component;
* 微信小程序手机号一键登录。
* <p>
* grant_type=wechat_applet,参数:loginCode(wx.login)、phoneCode(getPhoneNumber)。
* 流程:换 openid + 手机号 → 按手机号查小程序用户(blade_mp_user,不存在则拒绝)
* → 记录 openid → 按身份发令牌(不依赖系统角色)。
* 流程:换 openid + 手机号 → 由 {@link MpLoginSupport} 找到或创建账号并补齐档案
* → 按身份发令牌(不依赖系统角色)。
*/
@Slf4j
@Component
@@ -37,17 +34,17 @@ public class WechatMiniTokenGranter extends AbstractTokenGranter {
private final OAuth2UserService userService;
private final IWechatMiniService wechatMiniService;
private final IMpUserClient mpUserClient;
private final MpLoginSupport mpLoginSupport;
public WechatMiniTokenGranter(OAuth2ClientService clientService,
OAuth2UserService userService,
PasswordHandler passwordHandler,
IWechatMiniService wechatMiniService,
IMpUserClient mpUserClient) {
MpLoginSupport mpLoginSupport) {
super(clientService, userService, passwordHandler);
this.userService = userService;
this.wechatMiniService = wechatMiniService;
this.mpUserClient = mpUserClient;
this.mpLoginSupport = mpLoginSupport;
}
@Override
@@ -82,28 +79,12 @@ public class WechatMiniTokenGranter extends AbstractTokenGranter {
throw new UserInvalidException("未获取到微信手机号");
}
R<MpUserInfo> mpUserResult = mpUserClient.userInfoByPhone(request.getTenantId(), phone);
if (mpUserResult == null || !mpUserResult.isSuccess() || mpUserResult.getData() == null
|| mpUserResult.getData().getUser() == null) {
throw new UserInvalidException("用户不存在,无法登录");
}
OAuth2User user = TokenUtil.convertMpUser(mpUserResult.getData());
// 账号不存在时自动建号,建档与绑 openid 由编排层尽力而为,失败不阻断登录
OAuth2User user = mpLoginSupport.ensureLoginAccount(request.getTenantId(), phone, session.getOpenid());
if (!userService.validateUser(user)) {
throw new UserInvalidException("用户身份无效,无法登录");
}
R<Boolean> bindResult = mpUserClient.bindOpenId(
request.getTenantId(),
Func.toLong(user.getUserId()),
session.getOpenid()
);
if (bindResult == null || !bindResult.isSuccess()) {
String msg = bindResult != null ? bindResult.getMsg() : "绑定 openid 失败";
log.warn("绑定微信 openid 失败 userId={} openid={} msg={}", user.getUserId(), session.getOpenid(), msg);
throw new UserInvalidException(StringUtil.isBlank(msg) ? "绑定 openid 失败" : msg);
}
user.setClient(oauthClient);
return user;
}