增加支付宝小程序登录

This commit is contained in:
2025-08-15 01:28:14 +08:00
parent 30964f3b0d
commit 68142202b5
8 changed files with 343 additions and 22 deletions

View File

@ -228,6 +228,12 @@
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.110.ALL</version>
</dependency>
</dependencies>
<!-- Build Configuration -->

View File

@ -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<LoginResponse> wechatLogin(@RequestParam("code") String code) {
return Result.ok(userService.miniProgramLogin(code));
@ApiOperation(value = "获取支付宝手机号", notes = "获取支付宝手机号")
@PostMapping("/mini-program/alipay/getPhoneNumber")
public Result<String> getAlipayPhoneNumber(@RequestParam("authCode") String authCode) {
String phoneNumber = userService.getAlipayPhoneNumber(authCode);
return Result.ok(phoneNumber);
}
@ApiOperation(value = "支付宝小程序注册", notes = "支付宝小程序注册")
@PostMapping("/mini-program/alipay/register")
public Result<LoginResponse> 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<String> alipayLogin(@RequestParam("userId") String userId) {
String token = userService.alipayMiniProgramLogin(userId);
return Result.ok(token);
public Result<LoginResponse> 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("缺少必要的登录参数");
}
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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<String, Object> 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<BaseUserPO> 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<BaseUserPO> 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<String, Object> 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);
}

View File

@ -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<String, Object> 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<String, Object> 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<String, Object> getUserInfoByUserId(String userId) {
try {
// 这里可以调用支付宝的用户信息接口获取用户详情
// 为简化实现,直接返回基础信息
Map<String, Object> 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<String, Object> userInfo = getUserInfoByAuthCode(authCode);
return (String) userInfo.get("mobile");
} catch (Exception e) {
log.error("获取支付宝手机号异常", e);
throw new BizException("获取支付宝手机号异常");
}
}
}

View File

@ -69,4 +69,14 @@ wechat:
apiurl: https://api.weixin.qq.com
appid: wx25e1ad1a70c326de
secret: e0633b08d915a844f7ae7e4495d9e854
grantType: authorization_code
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