diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index 404b9ae3..e97b01b8 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -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 getAccessToken() { return success(authService.getAccessToken()); } - + @PermitAll @PostMapping("/get-session") @Operation(summary = "小程序session获取") public CommonResult getSession(@RequestBody @Valid WxLoginReqVO reqVO) { return success(authService.getSession(reqVO)); } + @PermitAll @PostMapping("/get-phone-number") @Operation(summary = "小程序手机号解密及绑定用户") - public CommonResult getPhoneNumber(@RequestBody @Valid WxLoginReqVO reqVO) { - return success(authService.getPhoneNumber(reqVO)); + public CommonResult getPhoneNumber(@RequestBody @Valid WxLoginReqVO reqVO) { + AuthLoginRespVO phoneNumber = authService.getPhoneNumber(reqVO); + if (phoneNumber != null) { + return success(phoneNumber); + } else { + return error(405, "该手机号不是平台用户"); + } } // ========== 短信登录相关 ========== diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxLoginReqVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxLoginReqVO.java index 8671d537..d8938b95 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxLoginReqVO.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxLoginReqVO.java @@ -19,7 +19,7 @@ public class WxLoginReqVO { private String iv; - private String session_key; + private String sessionKey; private String rawData; diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxUserPhoneRespVO.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxUserPhoneRespVO.java new file mode 100644 index 00000000..7963752d --- /dev/null +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/WxUserPhoneRespVO.java @@ -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; + } +} \ No newline at end of file diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java index bfebce24..57a1dd6c 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java @@ -91,5 +91,5 @@ public interface AdminAuthService { String getAccessToken(); - WxLoginRespVO getPhoneNumber(@Valid WxLoginReqVO reqVO); + AuthLoginRespVO getPhoneNumber(@Valid WxLoginReqVO reqVO); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index f409befe..9a5469e1 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -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); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index 947c7237..b3647b3f 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -214,4 +214,5 @@ public interface AdminUserService { */ boolean isPasswordMatch(String rawPassword, String encodedPassword); + void updateByid(AdminUserDO user); } diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index c0a7a0de..db27e60a 100644 --- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -569,6 +569,11 @@ public class AdminUserServiceImpl implements AdminUserService { return passwordEncoder.matches(rawPassword, encodedPassword); } + @Override + public void updateByid(AdminUserDO user) { + userMapper.updateById(user); + } + /** * 对密码进行加密 *