fix: 微信登录,接口修改。

This commit is contained in:
tianyongbao
2026-01-18 20:23:15 +08:00
parent 32844af3dd
commit a2e6579a3a
4 changed files with 178 additions and 29 deletions

View File

@@ -40,6 +40,7 @@ import com.intc.web.service.SysLoginService;
import com.intc.web.service.SysRegisterService; import com.intc.web.service.SysRegisterService;
import com.intc.weixin.domain.bo.ReqWxLogin; import com.intc.weixin.domain.bo.ReqWxLogin;
import com.intc.weixin.service.WxLoginService; import com.intc.weixin.service.WxLoginService;
import com.intc.weixin.config.WxMaProperties;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -83,6 +84,9 @@ public class AuthController {
@Autowired(required = false) @Autowired(required = false)
private WxLoginService wxLoginService; private WxLoginService wxLoginService;
@Autowired(required = false)
private WxMaProperties wxMaProperties;
/** /**
* 登录方法 * 登录方法
@@ -250,14 +254,27 @@ public class AuthController {
/** /**
* 微信小程序登录 * 微信小程序登录
* *
* @param request 微信登录请求 * @param body 微信登录请求JSON字符串
* @return 结果 * @return 结果
*/ */
@ApiEncrypt @ApiEncrypt
@PostMapping("/wechat_login") @PostMapping("/wechat_login")
public R<AquUser> wechatLogin(@Validated @RequestBody ReqWxLogin request) { public R<LoginVo> wechatLogin(@RequestBody String body) {
try { try {
log.info("收到微信登录请求: clientId={}, tenantId={}", request.getClientId(), request.getTenantId()); ReqWxLogin request = JsonUtils.parseObject(body, ReqWxLogin.class);
ValidatorUtils.validate(request);
// 如果未传递 clientId使用默认配置的 clientId
if (StringUtils.isBlank(request.getClientId()) && wxMaProperties != null) {
request.setClientId(wxMaProperties.getDefaultClientId());
// 更新 body 中的 clientId
body = JsonUtils.toJsonString(request);
}
String clientId = request.getClientId();
String grantType = "wechat"; // 微信登录的授权类型
log.info("收到微信登录请求: clientId={}, tenantId={}", clientId, request.getTenantId());
// 1. 检查服务是否可用 // 1. 检查服务是否可用
if (wxLoginService == null) { if (wxLoginService == null) {
@@ -266,43 +283,33 @@ public class AuthController {
} }
// 2. 校验客户端 // 2. 校验客户端
SysClientVo client = clientService.queryByClientId(request.getClientId()); SysClientVo client = clientService.queryByClientId(clientId);
if (ObjectUtil.isNull(client)) { if (ObjectUtil.isNull(client)) {
log.error("客户端不存在: clientId={}", request.getClientId()); log.error("客户端不存在: clientId={}", clientId);
return R.fail(MessageUtils.message("auth.grant.type.error"));
}
// 校验 client 内是否包含 grantType
if (!StringUtils.contains(client.getGrantType(), grantType)) {
log.error("客户端不支持该授权类型: clientId={}, grantType={}", clientId, grantType);
return R.fail(MessageUtils.message("auth.grant.type.error")); return R.fail(MessageUtils.message("auth.grant.type.error"));
} }
if (!SystemConstants.NORMAL.equals(client.getStatus())) { if (!SystemConstants.NORMAL.equals(client.getStatus())) {
log.error("客户端已被禁用: clientId={}, status={}", request.getClientId(), client.getStatus()); log.error("客户端已被禁用: clientId={}, status={}", clientId, client.getStatus());
return R.fail(MessageUtils.message("auth.grant.type.blocked")); return R.fail(MessageUtils.message("auth.grant.type.blocked"));
} }
// 3. 校验租户 // 3. 校验租户
if (StringUtils.isNotBlank(request.getTenantId())) { if (StringUtils.isNotBlank(request.getTenantId())) {
try { loginService.checkTenant(request.getTenantId());
loginService.checkTenant(request.getTenantId());
} catch (Exception e) {
log.error("租户校验失败: tenantId={}", request.getTenantId(), e);
return R.fail("租户校验失败: " + e.getMessage());
}
} }
// 4. 执行微信登录 // 4. 使用标准的 IAuthStrategy 登录方法
AquUser aquUser = wxLoginService.loginByWeChat( LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
request.getCode(),
request.getJsCode(), log.info("微信登录成功: userId={}, accessToken={}",
request.getTenantId() loginVo.getUserId(), loginVo.getAccessToken() != null ? "***" : "null");
);
if (aquUser == null) { return R.ok(loginVo);
log.error("微信登录失败,未返回用户信息");
return R.fail("登录失败,请重试");
}
// 5. 返回用户信息
log.info("微信登录成功: userId={}, mobilePhone={}",
aquUser.getId(), aquUser.getMobilePhone());
return R.ok(aquUser);
} catch (ServiceException e) { } catch (ServiceException e) {
log.error("微信登录业务异常: {}", e.getMessage(), e); log.error("微信登录业务异常: {}", e.getMessage(), e);

View File

@@ -0,0 +1,136 @@
package com.intc.web.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.intc.common.core.constant.SystemConstants;
import com.intc.common.core.domain.model.LoginUser;
import com.intc.common.core.exception.ServiceException;
import com.intc.common.core.exception.user.UserException;
import com.intc.common.core.utils.StringUtils;
import com.intc.common.core.utils.ValidatorUtils;
import com.intc.common.json.utils.JsonUtils;
import com.intc.common.satoken.utils.LoginHelper;
import com.intc.common.tenant.helper.TenantHelper;
import com.intc.fishery.domain.AquUser;
import com.intc.system.domain.SysUser;
import com.intc.system.domain.vo.SysClientVo;
import com.intc.system.domain.vo.SysUserVo;
import com.intc.system.mapper.SysUserMapper;
import com.intc.web.domain.vo.LoginVo;
import com.intc.web.service.IAuthStrategy;
import com.intc.web.service.SysLoginService;
import com.intc.weixin.domain.bo.ReqWxLogin;
import com.intc.weixin.service.WxLoginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 微信小程序认证策略
*
* @author intc
*/
@Slf4j
@Service("wechat" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor
public class WechatAuthStrategy implements IAuthStrategy {
private final WxLoginService wxLoginService;
private final SysLoginService loginService;
private final SysUserMapper userMapper;
@Override
public LoginVo login(String body, SysClientVo client) {
ReqWxLogin loginBody = JsonUtils.parseObject(body, ReqWxLogin.class);
ValidatorUtils.validate(loginBody);
String tenantId = loginBody.getTenantId();
String code = loginBody.getCode();
String jsCode = loginBody.getJsCode();
// 在租户上下文中执行登录
AquUser[] aquUserHolder = new AquUser[1]; // 用于保存 AquUser
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
// 1. 调用微信登录服务获取或创建渔业用户用于获取手机号和openId
AquUser aquUser = wxLoginService.loginByWeChat(code, jsCode, tenantId);
if (aquUser == null) {
log.error("微信登录失败,未返回用户信息");
throw new ServiceException("登录失败,请重试");
}
aquUserHolder[0] = aquUser; // 保存以便后续使用
log.info("获取微信用户信息成功: aquUserId={}, mobilePhone={}",
aquUser.getId(), aquUser.getMobilePhone());
// 2. 根据手机号查询系统用户
String mobilePhone = aquUser.getMobilePhone();
if (StringUtils.isBlank(mobilePhone)) {
log.error("微信用户手机号为空: aquUserId={}", aquUser.getId());
throw new ServiceException("获取手机号失败,请重新授权");
}
SysUserVo sysUser = loadUserByPhone(mobilePhone);
log.info("找到对应的系统用户: sysUserId={}, userName={}",
sysUser.getUserId(), sysUser.getUserName());
// 3. 使用系统用户构建 LoginUser包含完整的权限信息
return loginService.buildLoginUser(sysUser);
});
// 3. 设置客户端信息
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
// 4. 配置登录参数
SaLoginParameter model = new SaLoginParameter();
model.setDeviceType(client.getDeviceType());
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 5. 执行登录,生成 token
LoginHelper.login(loginUser, model);
// 6. 构建返回对象
LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
loginVo.setOpenid(aquUserHolder[0].getWxOpenId()); // 从 AquUser 中获取 openId
loginVo.setUserId(loginUser.getUserId());
loginVo.setUserName(loginUser.getUsername());
loginVo.setNickName(loginUser.getNickname());
return loginVo;
}
/**
* 根据手机号加载系统用户
*
* @param phone 手机号
* @return 系统用户信息
*/
private SysUserVo loadUserByPhone(String phone) {
SysUserVo user = userMapper.selectVoOne(
new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getPhonenumber, phone)
);
if (ObjectUtil.isNull(user)) {
log.error("系统中不存在该手机号的用户: phone={}", phone);
throw new UserException("user.not.exists", phone);
}
if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.error("用户已被停用: phone={}, userId={}", phone, user.getUserId());
throw new UserException("user.blocked", phone);
}
return user;
}
}

View File

@@ -39,4 +39,9 @@ public class WxMaProperties {
*/ */
private String msgDataFormat; private String msgDataFormat;
/**
* 默认客户端ID小程序登录使用
*/
private String defaultClientId = "miniapp-client";
} }

View File

@@ -1,5 +1,6 @@
package com.intc.weixin.domain.bo; package com.intc.weixin.domain.bo;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
@@ -27,12 +28,12 @@ public class ReqWxLogin implements Serializable {
* 登录时获取的jsCode用于获取openId * 登录时获取的jsCode用于获取openId
*/ */
@NotBlank(message = "jsCode不能为空") @NotBlank(message = "jsCode不能为空")
@JsonProperty("js_code")
private String jsCode; private String jsCode;
/** /**
* 客户端ID * 客户端ID
*/ */
@NotBlank(message = "客户端ID不能为空")
private String clientId; private String clientId;
/** /**