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