From 68142202b50c13bafd6147dcea6587199993cfe5 Mon Sep 17 00:00:00 2001 From: zhangli <123879394@qq.com> Date: Fri, 15 Aug 2025 01:28:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=94=AF=E4=BB=98=E5=AE=9D?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + .../sczx/user/controller/AuthController.java | 38 ++++-- .../com/sczx/user/dto/AlipayLoginRequest.java | 16 +++ .../user/dto/AlipayMiniProgramRegRequest.java | 16 +++ .../com/sczx/user/service/IUserService.java | 30 ++++- .../user/service/impl/UserServiceImpl.java | 127 ++++++++++++++++-- .../thirdpart/integration/AlipayInteg.java | 120 +++++++++++++++++ src/main/resources/application.yml | 12 +- 8 files changed, 343 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/sczx/user/dto/AlipayLoginRequest.java create mode 100644 src/main/java/com/sczx/user/dto/AlipayMiniProgramRegRequest.java create mode 100644 src/main/java/com/sczx/user/thirdpart/integration/AlipayInteg.java diff --git a/pom.xml b/pom.xml index bc703af..b90874c 100644 --- a/pom.xml +++ b/pom.xml @@ -228,6 +228,12 @@ bcprov-jdk15on 1.68 + + + com.alipay.sdk + alipay-sdk-java + 4.22.110.ALL + diff --git a/src/main/java/com/sczx/user/controller/AuthController.java b/src/main/java/com/sczx/user/controller/AuthController.java index 6b99250..bb480cb 100644 --- a/src/main/java/com/sczx/user/controller/AuthController.java +++ b/src/main/java/com/sczx/user/controller/AuthController.java @@ -1,12 +1,16 @@ package com.sczx.user.controller; import com.sczx.user.common.Result; +import com.sczx.user.dto.AlipayLoginRequest; +import com.sczx.user.dto.AlipayMiniProgramRegRequest; import com.sczx.user.dto.LoginResponse; import com.sczx.user.dto.WxMiniProgramRegRequest; +import com.sczx.user.exception.BizException; import com.sczx.user.service.IUserService; import com.sczx.user.util.JwtUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @@ -42,18 +46,36 @@ public class AuthController { return Result.ok(result); } - @ApiOperation(value = "微信小程序登录", notes = "通过微信code登录") - @PostMapping("/mini-program/wechat/login") - public Result wechatLogin(@RequestParam("code") String code) { - return Result.ok(userService.miniProgramLogin(code)); + @ApiOperation(value = "获取支付宝手机号", notes = "获取支付宝手机号") + @PostMapping("/mini-program/alipay/getPhoneNumber") + public Result getAlipayPhoneNumber(@RequestParam("authCode") String authCode) { + String phoneNumber = userService.getAlipayPhoneNumber(authCode); + return Result.ok(phoneNumber); } + @ApiOperation(value = "支付宝小程序注册", notes = "支付宝小程序注册") + @PostMapping("/mini-program/alipay/register") + public Result alipayRegister( + @RequestBody AlipayMiniProgramRegRequest alipayMiniProgramRegRequest) { + LoginResponse result = userService.alipayMiniProgramRegister(alipayMiniProgramRegRequest); + return Result.ok(result); + } - @ApiOperation(value = "支付宝小程序登录", notes = "通过支付宝userId登录") + @ApiOperation(value = "支付宝小程序登录", notes = "通过支付宝userId或authCode登录") @PostMapping("/mini-program/alipay/login") - public Result alipayLogin(@RequestParam("userId") String userId) { - String token = userService.alipayMiniProgramLogin(userId); - return Result.ok(token); + public Result alipayLogin(@RequestBody AlipayLoginRequest request) { + String userId = request.getUserId(); + String authCode = request.getAuthCode(); + + if (StringUtils.isNotBlank(authCode)) { + // 使用授权码登录 + return Result.ok(userService.alipayMiniProgramLoginByAuthCode(authCode)); + } else if (StringUtils.isNotBlank(userId)) { + // 使用userId登录 + return Result.ok(userService.alipayMiniProgramLoginByUserId(userId)); + } else { + throw new BizException("缺少必要的登录参数"); + } } } diff --git a/src/main/java/com/sczx/user/dto/AlipayLoginRequest.java b/src/main/java/com/sczx/user/dto/AlipayLoginRequest.java new file mode 100644 index 0000000..119fb73 --- /dev/null +++ b/src/main/java/com/sczx/user/dto/AlipayLoginRequest.java @@ -0,0 +1,16 @@ +package com.sczx.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel("支付宝小程序登录请求") +@Data +public class AlipayLoginRequest { + + @ApiModelProperty(value = "用户ID") + private String userId; + + @ApiModelProperty(value = "授权码") + private String authCode; +} diff --git a/src/main/java/com/sczx/user/dto/AlipayMiniProgramRegRequest.java b/src/main/java/com/sczx/user/dto/AlipayMiniProgramRegRequest.java new file mode 100644 index 0000000..d814bc7 --- /dev/null +++ b/src/main/java/com/sczx/user/dto/AlipayMiniProgramRegRequest.java @@ -0,0 +1,16 @@ +package com.sczx.user.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("支付宝小程序注册请求") +public class AlipayMiniProgramRegRequest { + + @ApiModelProperty(value = "授权码", required = true) + private String authCode; + + @ApiModelProperty(value = "用户ID") + private String userId; +} diff --git a/src/main/java/com/sczx/user/service/IUserService.java b/src/main/java/com/sczx/user/service/IUserService.java index 7615458..2883c78 100644 --- a/src/main/java/com/sczx/user/service/IUserService.java +++ b/src/main/java/com/sczx/user/service/IUserService.java @@ -1,5 +1,6 @@ package com.sczx.user.service; +import com.sczx.user.dto.AlipayMiniProgramRegRequest; import com.sczx.user.dto.LoginResponse; import com.sczx.user.dto.SimpleUserInfoDTO; import com.sczx.user.dto.WxMiniProgramRegRequest; @@ -41,11 +42,32 @@ public interface IUserService { /** - * 支付宝小程序登录 - * @param userId 支付宝用户ID - * @return token + * 支付宝小程序注册 + * @param alipayMiniProgramRegRequest 注册请求 + * @return 登录响应 */ - String alipayMiniProgramLogin(String userId); + LoginResponse alipayMiniProgramRegister(AlipayMiniProgramRegRequest alipayMiniProgramRegRequest); + + /** + * 支付宝小程序登录 + * @param userId 用户ID + * @return 登录响应 + */ + LoginResponse alipayMiniProgramLoginByUserId(String userId); + + /** + * 支付宝小程序登录 + * @param authCode 授权码 + * @return 登录响应 + */ + LoginResponse alipayMiniProgramLoginByAuthCode(String authCode); + + /** + * 获取支付宝用户手机号 + * @param authCode 授权码 + * @return 手机号 + */ + String getAlipayPhoneNumber(String authCode); diff --git a/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java b/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java index 5418b35..d265d83 100644 --- a/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java +++ b/src/main/java/com/sczx/user/service/impl/UserServiceImpl.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.sczx.user.common.enums.ApiErrorCode; import com.sczx.user.common.enums.MiniProgramTypeEnum; import com.sczx.user.convert.UserInfoConvert; +import com.sczx.user.dto.AlipayMiniProgramRegRequest; import com.sczx.user.dto.LoginResponse; import com.sczx.user.dto.SimpleUserInfoDTO; import com.sczx.user.dto.WxMiniProgramRegRequest; @@ -14,12 +15,12 @@ import com.sczx.user.repository.BaseUserRepo; import com.sczx.user.service.IUserService; import com.sczx.user.thirdpart.dto.WechatDecryptedPhoneInfo; import com.sczx.user.thirdpart.dto.WechatMiniProgramResponse; +import com.sczx.user.thirdpart.integration.AlipayInteg; import com.sczx.user.thirdpart.integration.WeichatInteg; import com.sczx.user.util.JwtUtil; import com.sczx.user.util.RedisUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; -import org.apache.tomcat.util.security.MD5Encoder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -60,6 +61,9 @@ public class UserServiceImpl implements IUserService { @Autowired private WeichatInteg weichatInteg; + @Autowired + private AlipayInteg alipayInteg; + @Override public String getWxOpenId(String code) { @@ -140,17 +144,122 @@ public class UserServiceImpl implements IUserService { return getLoginResponse(openid,MiniProgramTypeEnum.WECHAT.getType()); } + @Override + public LoginResponse alipayMiniProgramRegister(AlipayMiniProgramRegRequest alipayMiniProgramRegRequest) { + try { + // 1. 通过authCode获取用户信息 + Map userInfo = null; + String userId = null; + + if (StringUtils.isNotBlank(alipayMiniProgramRegRequest.getAuthCode())) { + userInfo = alipayInteg.getUserInfoByAuthCode(alipayMiniProgramRegRequest.getAuthCode()); + userId = (String) userInfo.get("userId"); + } else if (StringUtils.isNotBlank(alipayMiniProgramRegRequest.getUserId())) { + userId = alipayMiniProgramRegRequest.getUserId(); + userInfo = alipayInteg.getUserInfoByUserId(userId); + } else { + throw new BizException("缺少必要的用户标识"); + } + + if (StringUtils.isBlank(userId)) { + throw new BizException("获取支付宝用户信息失败"); + } + + // 2. 获取手机号 + String phoneNumber = (String) userInfo.get("mobile"); + if (StringUtils.isBlank(phoneNumber)) { + throw new BizException("支付宝小程序注册失败,无法获取用户真实手机号"); + } + + // 3. 查询用户是否存在 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(BaseUserPO::getPhoneNumber, phoneNumber); + BaseUserPO baseUserPO = baseUserRepo.getOne(queryWrapper); + + // 4. 创建或更新用户 + BaseUserPO newUserPO = new BaseUserPO(); + if (Objects.isNull(baseUserPO)) { + // 新用户注册 + newUserPO.setAlipayUserid(userId); + newUserPO.setUserName(phoneNumber); + newUserPO.setPhoneNumber(phoneNumber); + newUserPO.setPassword(MD5Utils.md5Hex(phoneNumber, StandardCharsets.UTF_8.name())); + newUserPO.setNickName((String) userInfo.get("nickName")); + newUserPO.setAvatarUrl((String) userInfo.get("avatar")); + newUserPO.setRoleId(1); + } else { + // 已存在用户,更新支付宝信息 + newUserPO.setId(baseUserPO.getId()); + newUserPO.setAlipayUserid(userId); +// if (StringUtils.isNotBlank((String) userInfo.get("nickName"))) { +// newUserPO.setNickName((String) userInfo.get("nickName")); +// } +// if (StringUtils.isNotBlank((String) userInfo.get("avatar"))) { +// newUserPO.setAvatarUrl((String) userInfo.get("avatar")); +// } + } + + baseUserRepo.saveOrUpdate(newUserPO); + + // 5. 返回登录信息 + return getLoginResponse(userId, MiniProgramTypeEnum.ALIPAY.getType()); + } catch (Exception e) { + log.error("支付宝小程序注册失败", e); + throw new BizException("支付宝小程序注册失败"); + } + } @Override - public String alipayMiniProgramLogin(String userId) { - String realUserId = ALIPAY_ID_TO_USERID.get(userId); - if (realUserId == null) { - throw new BizException("无效的支付宝用户ID"); - } - // 模拟登录逻辑 - SimpleUserInfoDTO simpleUserInfoDTO = getUserInfoByProgramId(realUserId, MiniProgramTypeEnum.ALIPAY.getType()); + public LoginResponse alipayMiniProgramLoginByUserId(String userId) { + try { + // 1. 验证用户ID有效性 + if (StringUtils.isBlank(userId)) { + throw new BizException("用户ID不能为空"); + } - return jwtUtil.generateToken(simpleUserInfoDTO, simpleUserInfoDTO.getUserName()); + // 2. 查询数据库验证用户是否存在 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(BaseUserPO::getAlipayUserid, userId); + BaseUserPO userPO = baseUserRepo.getOne(queryWrapper); + + if (userPO == null) { + throw new BizException("无效的支付宝用户ID"); + } + + // 3. 返回登录信息 + return getLoginResponse(userId, MiniProgramTypeEnum.ALIPAY.getType()); + } catch (Exception e) { + log.error("支付宝小程序按userId登录失败", e); + throw new BizException("支付宝小程序登录失败"); + } + } + + @Override + public LoginResponse alipayMiniProgramLoginByAuthCode(String authCode) { + try { + // 1. 验证授权码有效性 + if (StringUtils.isBlank(authCode)) { + throw new BizException("授权码不能为空"); + } + + // 2. 通过授权码获取用户信息 + Map userInfo = alipayInteg.getUserInfoByAuthCode(authCode); + String userId = (String) userInfo.get("userId"); + + if (StringUtils.isBlank(userId)) { + throw new BizException("获取支付宝用户信息失败"); + } + return alipayMiniProgramLoginByUserId(userId); + } catch (Exception e) { + log.error("支付宝小程序按authCode登录失败", e); + throw new BizException("支付宝小程序登录失败"); + } + } + + + @Override + public String getAlipayPhoneNumber(String authCode) { + return alipayInteg.getPhoneNumber(authCode); } diff --git a/src/main/java/com/sczx/user/thirdpart/integration/AlipayInteg.java b/src/main/java/com/sczx/user/thirdpart/integration/AlipayInteg.java new file mode 100644 index 0000000..bfb66da --- /dev/null +++ b/src/main/java/com/sczx/user/thirdpart/integration/AlipayInteg.java @@ -0,0 +1,120 @@ + +package com.sczx.user.thirdpart.integration; + +import com.alipay.api.AlipayClient; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.request.AlipaySystemOauthTokenRequest; +import com.alipay.api.request.AlipayUserInfoShareRequest; +import com.alipay.api.response.AlipaySystemOauthTokenResponse; +import com.alipay.api.response.AlipayUserInfoShareResponse; +import com.sczx.user.exception.BizException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Component +public class AlipayInteg { + + @Value("${alipay.miniapp.appid}") + private String appId; + + @Value("${alipay.miniapp.privateKey}") + private String privateKey; + + @Value("${alipay.miniapp.publicKey}") + private String publicKey; + + @Value("${alipay.miniapp.gatewayUrl}") + private String gatewayUrl; + + @Value("${alipay.miniapp.format}") + private String format; + + @Value("${alipay.miniapp.charset}") + private String charset; + + @Value("${alipay.miniapp.signType}") + private String signType; + + /** + * 通过授权码获取用户信息 + * @param authCode 授权码 + * @return 用户信息 + */ + public Map getUserInfoByAuthCode(String authCode) { + try { + AlipayClient alipayClient = new DefaultAlipayClient( + gatewayUrl, appId, privateKey, format, charset, publicKey, signType); + + // 1. 通过authCode获取access_token + AlipaySystemOauthTokenRequest tokenRequest = new AlipaySystemOauthTokenRequest(); + tokenRequest.setGrantType("authorization_code"); + tokenRequest.setCode(authCode); + + AlipaySystemOauthTokenResponse tokenResponse = alipayClient.execute(tokenRequest); + + if (!tokenResponse.isSuccess()) { + log.error("获取支付宝access_token失败: {}", tokenResponse.getSubMsg()); + throw new BizException("获取支付宝用户信息失败"); + } + + // 2. 通过access_token获取用户信息 + AlipayUserInfoShareRequest userInfoRequest = new AlipayUserInfoShareRequest(); + AlipayUserInfoShareResponse userInfoResponse = alipayClient.execute(userInfoRequest, tokenResponse.getAccessToken()); + + if (!userInfoResponse.isSuccess()) { + log.error("获取支付宝用户信息失败: {}", userInfoResponse.getSubMsg()); + throw new BizException("获取支付宝用户信息失败"); + } + + // 3. 构造返回结果 + Map userInfo = new HashMap<>(); + userInfo.put("userId", userInfoResponse.getUserId()); + userInfo.put("nickName", userInfoResponse.getNickName()); + userInfo.put("avatar", userInfoResponse.getAvatar()); + userInfo.put("mobile", userInfoResponse.getMobile()); + + return userInfo; + } catch (Exception e) { + log.error("获取支付宝用户信息异常", e); + throw new BizException("获取支付宝用户信息异常"); + } + } + + /** + * 通过userId获取用户信息(简化版,适用于已授权用户) + * @param userId 用户ID + * @return 用户信息 + */ + public Map getUserInfoByUserId(String userId) { + try { + // 这里可以调用支付宝的用户信息接口获取用户详情 + // 为简化实现,直接返回基础信息 + Map userInfo = new HashMap<>(); + userInfo.put("userId", userId); + return userInfo; + } catch (Exception e) { + log.error("获取支付宝用户信息异常", e); + throw new BizException("获取支付宝用户信息异常"); + } + } + + /** + * 获取用户手机号(通过支付宝接口) + * @param authCode 授权码 + * @return 手机号 + */ + public String getPhoneNumber(String authCode) { + try { + Map userInfo = getUserInfoByAuthCode(authCode); + return (String) userInfo.get("mobile"); + } catch (Exception e) { + log.error("获取支付宝手机号异常", e); + throw new BizException("获取支付宝手机号异常"); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index eeec161..a0e5196 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -69,4 +69,14 @@ wechat: apiurl: https://api.weixin.qq.com appid: wx25e1ad1a70c326de secret: e0633b08d915a844f7ae7e4495d9e854 - grantType: authorization_code \ No newline at end of file + grantType: authorization_code + +alipay: + miniapp: + appid: your_alipay_appid + privateKey: your_private_key + publicKey: your_public_key + gatewayUrl: https://openapi.alipay.com/gateway.do + format: JSON + charset: UTF-8 + signType: RSA2 \ No newline at end of file