farm模块-小程序登录

This commit is contained in:
顾君禹
2025-09-04 22:27:21 +08:00
parent 3b3bedb7d0
commit f4961f798c
7 changed files with 77 additions and 22 deletions

View File

@@ -35,6 +35,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@@ -123,23 +124,30 @@ public class AuthController {
}
// ========== 小程序登录相关 ==========
@PermitAll
@PostMapping("/get-access-token")
@Operation(summary = "小程序调用凭据")
public CommonResult<String> getAccessToken() {
return success(authService.getAccessToken());
}
@PermitAll
@PostMapping("/get-session")
@Operation(summary = "小程序session获取")
public CommonResult<WxLoginRespVO> getSession(@RequestBody @Valid WxLoginReqVO reqVO) {
return success(authService.getSession(reqVO));
}
@PermitAll
@PostMapping("/get-phone-number")
@Operation(summary = "小程序手机号解密及绑定用户")
public CommonResult<WxLoginRespVO> getPhoneNumber(@RequestBody @Valid WxLoginReqVO reqVO) {
return success(authService.getPhoneNumber(reqVO));
public CommonResult<AuthLoginRespVO> getPhoneNumber(@RequestBody @Valid WxLoginReqVO reqVO) {
AuthLoginRespVO phoneNumber = authService.getPhoneNumber(reqVO);
if (phoneNumber != null) {
return success(phoneNumber);
} else {
return error(405, "该手机号不是平台用户");
}
}
// ========== 短信登录相关 ==========

View File

@@ -19,7 +19,7 @@ public class WxLoginReqVO {
private String iv;
private String session_key;
private String sessionKey;
private String rawData;

View File

@@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.controller.admin.auth.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Schema(description = "解密手机号")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class WxUserPhoneRespVO {
private String phoneNumber;
private String purePhoneNumber;
private String countryCode;
private Watermark watermark;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Watermark {
private String timestamp;
private String appid;
}
}

View File

@@ -91,5 +91,5 @@ public interface AdminAuthService {
String getAccessToken();
WxLoginRespVO getPhoneNumber(@Valid WxLoginReqVO reqVO);
AuthLoginRespVO getPhoneNumber(@Valid WxLoginReqVO reqVO);
}

View File

@@ -342,16 +342,25 @@ public class AdminAuthServiceImpl implements AdminAuthService {
}
@Override
public WxLoginRespVO getPhoneNumber(WxLoginReqVO reqVO) {
public AuthLoginRespVO getPhoneNumber(WxLoginReqVO reqVO) {
try {
// 解密手机号数据
String decryptedData = decryptWxData(reqVO.getEncryptedData(), reqVO.getSession_key(), reqVO.getIv(), wxMiniAppId);
// 解析JSON数据并返回
return JSONUtil.toBean(decryptedData, WxLoginRespVO.class);
String decryptedData = decryptWxData(reqVO.getEncryptedData(), reqVO.getSessionKey(), reqVO.getIv(), wxMiniAppId);
// 解析JSON数据
WxUserPhoneRespVO bean = JSONUtil.toBean(decryptedData, WxUserPhoneRespVO.class);
// 绑定用户
String phoneNumber = bean.getPhoneNumber();
AdminUserDO user = userService.getUserByMobile(phoneNumber);
if (user == null) {
return null;
}
user.setOpenid(reqVO.getOpenid());
userService.updateByid(user);
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME);
} catch (Exception e) {
log.error("[getPhoneNumber][解密手机号失败,encryptedData: {}, sessionKey: {}, iv: {}]",
reqVO.getEncryptedData(), reqVO.getSession_key(), reqVO.getIv(), e);
log.error("[getPhoneNumber][解密手机号失败,encryptedData: {}, sessionKey: {}, iv: {}]",
reqVO.getEncryptedData(), reqVO.getSessionKey(), reqVO.getIv(), e);
throw new RuntimeException("解密手机号失败", e);
}
}
@@ -360,11 +369,11 @@ public class AdminAuthServiceImpl implements AdminAuthService {
* 解密微信小程序数据
* 根据微信官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
* 参考Node.js实现:WXBizDataCrypt
*
*
* @param encryptedData 加密数据
* @param sessionKey 会话密钥
* @param iv 初始向量
* @param appId 小程序appId
* @param sessionKey 会话密钥
* @param iv 初始向量
* @param appId 小程序appId
* @return 解密后的数据
*/
private String decryptWxData(String encryptedData, String sessionKey, String iv, String appId) {
@@ -373,25 +382,25 @@ public class AdminAuthServiceImpl implements AdminAuthService {
byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
byte[] ivBytes = Base64.getDecoder().decode(iv);
// 2. 使用AES-128-CBC解密
AES aes = new AES("CBC", "PKCS7Padding", sessionKeyBytes, ivBytes);
byte[] decryptedBytes = aes.decrypt(encryptedBytes);
// 3. 转换为字符串
String decoded = new String(decryptedBytes, StandardCharsets.UTF_8);
// 4. 解析JSON并验证watermark
cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(decoded);
cn.hutool.json.JSONObject watermark = jsonObject.getJSONObject("watermark");
if (watermark == null || !appId.equals(watermark.getStr("appid"))) {
throw new RuntimeException("Illegal Buffer: watermark appid验证失败");
}
return decoded;
} catch (Exception e) {
log.error("[decryptWxData][解密失败,encryptedData: {}, sessionKey: {}, iv: {}, appId: {}]",
log.error("[decryptWxData][解密失败,encryptedData: {}, sessionKey: {}, iv: {}, appId: {}]",
encryptedData, sessionKey, iv, appId, e);
throw new RuntimeException("Illegal Buffer: 数据解密失败", e);
}

View File

@@ -214,4 +214,5 @@ public interface AdminUserService {
*/
boolean isPasswordMatch(String rawPassword, String encodedPassword);
void updateByid(AdminUserDO user);
}

View File

@@ -569,6 +569,11 @@ public class AdminUserServiceImpl implements AdminUserService {
return passwordEncoder.matches(rawPassword, encodedPassword);
}
@Override
public void updateByid(AdminUserDO user) {
userMapper.updateById(user);
}
/**
* 对密码进行加密
*