支付宝小程序登录和注册接口

This commit is contained in:
2025-08-16 01:22:42 +08:00
parent 85d5259195
commit 1694cddabc
8 changed files with 111 additions and 173 deletions

View File

@ -232,7 +232,7 @@
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.110.ALL</version>
<version>4.34.0.ALL</version>
</dependency>
</dependencies>

View File

@ -7,8 +7,8 @@ import lombok.Getter;
*/
@Getter
public enum MiniProgramTypeEnum {
WECHAT("wechat"),
ALIPAY("alipay");
WECHAT("WECHAT"),
ALIPAY("ALIPAY");
private final String type;

View File

@ -1,16 +1,13 @@
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.*;
@ -46,36 +43,14 @@ public class AuthController {
return Result.ok(result);
}
@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(
@ApiOperation(value = "支付宝小程序登录", notes = "支付宝小程序登录")
@PostMapping("/mini-program/alipayLogin")
public Result<LoginResponse> alipayLogin(
@RequestBody AlipayMiniProgramRegRequest alipayMiniProgramRegRequest) {
LoginResponse result = userService.alipayMiniProgramRegister(alipayMiniProgramRegRequest);
LoginResponse result = userService.alipayMiniProgramLoginOrReg(alipayMiniProgramRegRequest);
return Result.ok(result);
}
@ApiOperation(value = "支付宝小程序登录", notes = "通过支付宝userId或authCode登录")
@PostMapping("/mini-program/alipay/login")
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

@ -8,9 +8,9 @@ import lombok.Data;
@ApiModel("支付宝小程序注册请求")
public class AlipayMiniProgramRegRequest {
@ApiModelProperty(value = "授权码", required = true)
private String authCode;
@ApiModelProperty(value = "加密数据")
private String encryptedData;
@ApiModelProperty(value = "用户ID")
private String userId;
@ApiModelProperty(value = "签名")
private String sign;
}

View File

@ -42,32 +42,13 @@ public interface IUserService {
/**
* 支付宝小程序注册
* @param alipayMiniProgramRegRequest 注册请求
* 支付宝小程序登录或注册
* @param alipayMiniProgramRegRequest 登录请求
* @return 登录响应
*/
LoginResponse alipayMiniProgramRegister(AlipayMiniProgramRegRequest alipayMiniProgramRegRequest);
LoginResponse alipayMiniProgramLoginOrReg(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

@ -25,8 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@ -39,16 +37,6 @@ import java.util.Optional;
@Service
public class UserServiceImpl implements IUserService {
// 模拟微信登录获取 openid
private static final Map<String, String> WECHAT_CODE_TO_OPENID = new HashMap<>();
private static final Map<String, String> ALIPAY_ID_TO_USERID = new HashMap<>();
static {
// 测试数据模拟
WECHAT_CODE_TO_OPENID.put("test_wx_code", "user_openid_1");
ALIPAY_ID_TO_USERID.put("test_alipay_id", "user_id_1");
}
@Autowired
private JwtUtil jwtUtil;
@ -145,132 +133,40 @@ public class UserServiceImpl implements IUserService {
}
@Override
public LoginResponse alipayMiniProgramRegister(AlipayMiniProgramRegRequest alipayMiniProgramRegRequest) {
public LoginResponse alipayMiniProgramLoginOrReg(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");
String phoneNumber = alipayInteg.getPhoneNumberFromEncryptedData(alipayMiniProgramRegRequest.getEncryptedData(), alipayMiniProgramRegRequest.getSign());
if (StringUtils.isBlank(phoneNumber)) {
throw new BizException("支付宝小程序注册失败,无法获取用户真实手机号");
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)) {
baseUserPO =new 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"));
// }
baseUserPO.setUserName(phoneNumber);
baseUserPO.setPhoneNumber(phoneNumber);
baseUserPO.setPassword(MD5Utils.md5Hex(phoneNumber, StandardCharsets.UTF_8.name()));
baseUserPO.setRoleId(1);
baseUserRepo.saveOrUpdate(baseUserPO);
}
baseUserRepo.saveOrUpdate(newUserPO);
// 5. 返回登录信息
return getLoginResponse(userId, MiniProgramTypeEnum.ALIPAY.getType());
return getLoginResponse(baseUserPO,MiniProgramTypeEnum.ALIPAY);
} catch (Exception e) {
log.error("支付宝小程序注册失败", e);
throw new BizException("支付宝小程序注册失败");
}
}
@Override
public LoginResponse alipayMiniProgramLoginByUserId(String userId) {
try {
// 1. 验证用户ID有效性
if (StringUtils.isBlank(userId)) {
throw new BizException("用户ID不能为空");
}
// 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);
}
@Override
public SimpleUserInfoDTO getUserInfoByProgramId(String programId, String programType) {
//todo 根据小程序id和类型查询用户信息
// SimpleUserInfoDTO simpleUserInfoDTO = new SimpleUserInfoDTO();
// simpleUserInfoDTO.setUserId(1);
// simpleUserInfoDTO.setUserName("张三");
// simpleUserInfoDTO.setRoleId(1);
// return simpleUserInfoDTO;
LambdaQueryWrapper<BaseUserPO> queryWrapper = new LambdaQueryWrapper<>();
if(MiniProgramTypeEnum.WECHAT.getType().equalsIgnoreCase(programType)){
@ -302,4 +198,23 @@ public class UserServiceImpl implements IUserService {
loginResponse.setUserInfo(simpleUserInfoDTO);
return loginResponse;
}
/**
* 获取登录信息
* @param baseUserPO
* @return
*/
private LoginResponse getLoginResponse(BaseUserPO baseUserPO,MiniProgramTypeEnum miniProgramTypeEnum) {
SimpleUserInfoDTO simpleUserInfoDTO = UserInfoConvert.INSTANCE.poToSimpleDTO(baseUserPO);
if(Objects.isNull(simpleUserInfoDTO)){
throw new BizException(ApiErrorCode.NO_REG);
}
simpleUserInfoDTO.setMiniProgramType(miniProgramTypeEnum.getType());
String token = jwtUtil.generateToken(simpleUserInfoDTO, simpleUserInfoDTO.getUserName());
LoginResponse loginResponse = new LoginResponse();
loginResponse.setToken(token);
loginResponse.setUserInfo(simpleUserInfoDTO);
return loginResponse;
}
}

View File

@ -1,8 +1,11 @@
package com.sczx.user.thirdpart.integration;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
@ -22,6 +25,12 @@ public class AlipayInteg {
@Value("${alipay.miniapp.appid}")
private String appId;
@Value("${alipay.miniapp.signVeriKey}")
private String signVeriKey;
@Value("${alipay.miniapp.decryptKey}")
private String decryptKey;
@Value("${alipay.miniapp.privateKey}")
private String privateKey;
@ -40,6 +49,61 @@ public class AlipayInteg {
@Value("${alipay.miniapp.signType}")
private String signType;
@Value("${alipay.miniapp.encryptType}")
private String encryptType;
/**
* 通过加密数据获取用户手机号
* @param encryptedData 加密数据
* @return 手机号
*/
public String getPhoneNumberFromEncryptedData(String encryptedData,String sign) {
try {
//1. 获取验签和解密所需要的参数
//判断是否为加密内容
boolean isDataEncrypted = !encryptedData.startsWith("{");
boolean signCheckPass = false;
//2. 验签
// String signContent = encryptedData;
// if (isDataEncrypted) {
// signContent = "\"" + signContent + "\"";
// }
// try {
// signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);
// } catch (AlipayApiException e) {
// // 验签异常, 日志
// log.error("验签异常");
// throw e;
// }
// if (!signCheckPass) {
// //验签不通过(异常或者报文被篡改),终止流程(不需要做解密)
// log.error("验签不通过(异常或者报文被篡改),终止流程(不需要做解密)");
// throw new Exception("验签失败");
// }
//3. 解密
String plainData = null;
if (isDataEncrypted) {
try {
plainData = AlipayEncrypt.decryptContent(encryptedData, encryptType, decryptKey, charset);
log.info("解密后的明文: {}", plainData);
JSONObject plainDataJson = JSONObject.parseObject(plainData);
return plainDataJson.getString("mobile");
} catch (AlipayApiException e) {
//解密异常, 记录日志
log.error("解密异常",e);
throw new Exception("解密异常");
}
} else {
plainData = encryptedData;
}
return plainData;
} catch (Exception e) {
log.error("获取支付宝手机号异常", e);
throw new BizException("获取支付宝手机号异常");
}
}
/**
* 通过授权码获取用户信息
* @param authCode 授权码

View File

@ -77,6 +77,9 @@ alipay:
privateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCs8bglD1hj36054iZA7R42Sn41mR6cn2EwcRVWbAAcAjkGgkwIu8CbnTgFdKmCmpqIInoBFPAGSIPPh3IIxV8TdUTz6gwW1ep8dpkuF935f1VA2pELPQd5HYhuMaedtjFA4AQ4zrPT3ZR82J4bTQfJTnJER/OMmQhzK4Z4aBsgEbWA+kuFexApGFBiqngTGB3gtfqqcos8v3SQlWRCcdwmSn6sKhDnNLplRcTZ3/YbNjvGL3e5NTYIsyJntWLY5nWDvFj7INDNMD8Kx694l5beszpPzIGOUQnCzLAQvlyjdiqklQgwh798uOFFGCP4lSrnDSxGpvf4KzBAciOBzvVDAgMBAAECggEAeunoyF4ZohHs2cDDE03zNP7IqGtE+GfF+VnFooBrq3xg7yFXzLUz9OVOVYJOn0YmIi7uqyooVS7gj3RiNZ2hLwEfmoNzSB+M4hygTcQkvRgkjU1J3MTpNMkql7auvEYqx0LvfThbUm6fBAQoipq6t/YK/EBu9jQlb0U18wl6jdUdHWY1imybltwaq3RA9efSwehovhP5NsZmDWg7piViPizzRe0vQCDNx+yKXZF5v33HgWaoxuIuEzioO/lCCtki8JLFe5rmELXHob8P956zYUm3AQE7+Dy80kIwHzSsDjKOWnBgSivDPf7u3D7aMZ21BM8b2VGU3ogUlznTzvJQ8QKBgQDVczfuhW4Ii81G4qOM+kEei4OrhmYQfk6CmTqLAsTb1dNcH06Ff791miPGJ6tWqIy6+Q1OVWID7BoHBu9UgwpVxRFKDGGFEQb2J67auQCb57CWNZx8w/4R/OnVSZ4WvoOPiokq/f6bJH7Snk6Zj806MjTXgO+6sFfjAB9srF3jlQKBgQDPa2gOZtQGBgHw2MYdyu7Y2aXCAgBp7ruI02iPrNLjvJnoHDpTJjUYmbLWyx1xnZnHVR5TCtZB4MNMZnhwbiKpsF5omxf4/31zc7JzQPoD/VjME8+LeJekW5telwqUCK4qKUcWLbW1QfSUwyNVnyN4QsQfp7W7fmLSfi+ACGa/dwKBgHY8l7wBn30ObAybGLvMGGxiHfLSxRDX1oeTd5FvXDrmTGlYUjezFwx+8NggO1IKlcIwmYVN2LiRfa1s0wA+gmgWfMhG6XI7h16thrdUCZlTE0dxtRiLvN6b+a+TUwYITHoj5G2zOukXo0TqOmHn/WgCTbEelC0W5+gvtjiNloitAoGBAIUGXlr2Kb6fNblwXUcYMiyTEZKmU/ucZ1uuMh4K+cmi2JYbHHDdTSo00JSe+Yg3Sjuj5Gnfxl/DtZ0XDuEUUVjAyxuNdEd2G8/igK0YHABZCA0CG5ZYRfDb634zok4kbwaNKJEZybKw1RpfOBcek9H6B+xBU/UmblyPHwme2b6rAoGADXnDQBlMmYKrK8+34E28E0tiUr7UAc6t86ZnzVoUEdZEkJ5EwRraR/QBqumu7/B0SrcME9VZH1P++BYnsR0lZLlu+CE54UJ1fSopjExpcAluIgZ2FkrKFLm0qGdzt58AW7SK4lFECJKdQaS9ZogVx7+htQ6vyv3bVv21u2FJ3Is=
publicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArPG4JQ9YY9+tOeImQO0eNkp+NZkenJ9hMHEVVmwAHAI5BoJMCLvAm504BXSpgpqaiCJ6ARTwBkiDz4dyCMVfE3VE8+oMFtXqfHaZLhfd+X9VQNqRCz0HeR2IbjGnnbYxQOAEOM6z092UfNieG00HyU5yREfzjJkIcyuGeGgbIBG1gPpLhXsQKRhQYqp4Exgd4LX6qnKLPL90kJVkQnHcJkp+rCoQ5zS6ZUXE2d/2GzY7xi93uTU2CLMiZ7Vi2OZ1g7xY+yDQzTA/CseveJeW3rM6T8yBjlEJwsywEL5co3YqpJUIMIe/fLjhRRgj+JUq5w0sRqb3+CswQHIjgc71QwIDAQAB
gatewayUrl: https://openapi.alipay.com/gateway.do
signVeriKey: 支付宝公钥
decryptKey: +MXY7LF6TPih7jf7AmtC2g==
format: JSON
charset: UTF-8
signType: RSA2
signType: RSA2
encryptType: AES