增加微信小程序注册接口
This commit is contained in:
5
pom.xml
5
pom.xml
@ -223,6 +223,11 @@
|
||||
<version>1.2.83</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<version>1.68</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- Build Configuration -->
|
||||
|
||||
@ -2,7 +2,7 @@ package com.sczx.user.controller;
|
||||
|
||||
import com.sczx.user.common.Result;
|
||||
import com.sczx.user.dto.LoginResponse;
|
||||
import com.sczx.user.dto.RegReq;
|
||||
import com.sczx.user.dto.WxMiniProgramRegRequest;
|
||||
import com.sczx.user.service.IUserService;
|
||||
import com.sczx.user.util.JwtUtil;
|
||||
import io.swagger.annotations.Api;
|
||||
@ -34,11 +34,11 @@ public class AuthController {
|
||||
return Result.ok(phoneNumber);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "小程序注册", notes = "注册")
|
||||
@PostMapping("/mini-program/register")
|
||||
public Result<Boolean> wechatRegister(
|
||||
@RequestBody RegReq regReq) {
|
||||
Boolean result = userService.miniProgramRegister(regReq.getOpenId(), regReq.getNickName(), regReq.getPhoneNumber(), regReq.getAvatarUrl());
|
||||
@ApiOperation(value = "微信小程序注册", notes = "微信小程序注册")
|
||||
@PostMapping("/mini-program/wechat/register")
|
||||
public Result<LoginResponse> wechatRegister(
|
||||
@RequestBody WxMiniProgramRegRequest wxMiniProgramRegRequest) {
|
||||
LoginResponse result = userService.wxMiniProgramRegister(wxMiniProgramRegRequest);
|
||||
return Result.ok(result);
|
||||
}
|
||||
|
||||
|
||||
24
src/main/java/com/sczx/user/dto/WxMiniProgramRegRequest.java
Normal file
24
src/main/java/com/sczx/user/dto/WxMiniProgramRegRequest.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.sczx.user.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel(value = "微信小程序注册请求")
|
||||
@Data
|
||||
public class WxMiniProgramRegRequest {
|
||||
@ApiModelProperty(value = "微信code")
|
||||
String code;
|
||||
|
||||
@ApiModelProperty(value = "微信手机号加密数据")
|
||||
String phoneEncryptedData;
|
||||
|
||||
@ApiModelProperty(value = "微信手机号加密数据iv")
|
||||
String phoneIv;
|
||||
|
||||
@ApiModelProperty(value = "微信用户加密数据")
|
||||
String userEncryptedData;
|
||||
|
||||
@ApiModelProperty(value = "微信手机号加密数据iv")
|
||||
String userIv;
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.sczx.user.service;
|
||||
|
||||
import com.sczx.user.dto.LoginResponse;
|
||||
import com.sczx.user.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.user.dto.WxMiniProgramRegRequest;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
@ -25,14 +26,11 @@ public interface IUserService {
|
||||
String getWxPhoneNumber(String phoneCode);
|
||||
|
||||
/**
|
||||
* 小程序注册
|
||||
* @param openId
|
||||
* @param userName
|
||||
* @param phoneNumber
|
||||
* @param avatarUrl
|
||||
* 微信小程序注册
|
||||
* @param wxMiniProgramRegRequest
|
||||
* @return
|
||||
*/
|
||||
Boolean miniProgramRegister(String openId, String userName,String phoneNumber,String avatarUrl);
|
||||
LoginResponse wxMiniProgramRegister(WxMiniProgramRegRequest wxMiniProgramRegRequest);
|
||||
/**
|
||||
* 微信小程序登录
|
||||
* @param code 微信登录code
|
||||
|
||||
@ -6,20 +6,26 @@ import com.sczx.user.common.enums.MiniProgramTypeEnum;
|
||||
import com.sczx.user.convert.UserInfoConvert;
|
||||
import com.sczx.user.dto.LoginResponse;
|
||||
import com.sczx.user.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.user.dto.WxMiniProgramRegRequest;
|
||||
import com.sczx.user.exception.BizException;
|
||||
import com.sczx.user.po.BaseUserPO;
|
||||
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.WechatDecryptedUserInfo;
|
||||
import com.sczx.user.thirdpart.dto.WechatMiniProgramResponse;
|
||||
import com.sczx.user.thirdpart.integ.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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
@ -65,22 +71,57 @@ public class UserServiceImpl implements IUserService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean miniProgramRegister(String openId, String nickName, String phoneNumber, String avatarUrl) {
|
||||
LambdaQueryWrapper<BaseUserPO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(BaseUserPO::getPhoneNumber, phoneNumber);
|
||||
BaseUserPO baseUserPO = baseUserRepo.getOne(queryWrapper);
|
||||
if(Objects.nonNull(baseUserPO)){
|
||||
throw new BizException("该手机号用户已注册");
|
||||
public LoginResponse wxMiniProgramRegister(WxMiniProgramRegRequest wxMiniProgramRegRequest) {
|
||||
try{
|
||||
// 1. 通过code获取session_key和openid
|
||||
WechatMiniProgramResponse sessionInfo = weichatInteg.getSessionInfoByCode(wxMiniProgramRegRequest.getCode());
|
||||
if (sessionInfo == null || sessionInfo.getOpenid() == null) {
|
||||
throw new BizException("获取微信用户信息失败");
|
||||
}
|
||||
|
||||
String openid = sessionInfo.getOpenid();
|
||||
String sessionKey = sessionInfo.getSession_key();
|
||||
|
||||
// 2. 解密手机号数据
|
||||
WechatDecryptedPhoneInfo phoneInfo = null;
|
||||
if (StringUtils.isNotBlank(wxMiniProgramRegRequest.getPhoneEncryptedData()) && StringUtils.isNotBlank(wxMiniProgramRegRequest.getPhoneIv())
|
||||
&& StringUtils.isNotBlank(sessionKey)) {
|
||||
phoneInfo = weichatInteg.decryptPhoneNumber(sessionKey, wxMiniProgramRegRequest.getPhoneEncryptedData(), wxMiniProgramRegRequest.getPhoneIv());
|
||||
}
|
||||
|
||||
// 3. 解密用户基本信息(昵称、头像等)
|
||||
WechatDecryptedUserInfo userInfo = null;
|
||||
if (StringUtils.isNotBlank(wxMiniProgramRegRequest.getUserEncryptedData()) && StringUtils.isNotBlank(wxMiniProgramRegRequest.getUserIv())
|
||||
&& StringUtils.isNotBlank(sessionKey)) {
|
||||
userInfo = weichatInteg.decryptUserInfo(sessionKey, wxMiniProgramRegRequest.getUserEncryptedData(), wxMiniProgramRegRequest.getUserIv());
|
||||
}
|
||||
|
||||
|
||||
LambdaQueryWrapper<BaseUserPO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(BaseUserPO::getPhoneNumber, phoneInfo.getPurePhoneNumber());
|
||||
BaseUserPO baseUserPO = baseUserRepo.getOne(queryWrapper);
|
||||
BaseUserPO newUserPO = new BaseUserPO();
|
||||
if(Objects.isNull(baseUserPO)){
|
||||
newUserPO.setWechatOpenid(openid);
|
||||
newUserPO.setUserName(phoneInfo.getPurePhoneNumber());
|
||||
newUserPO.setPhoneNumber(phoneInfo.getPurePhoneNumber());
|
||||
newUserPO.setPassword(MD5Utils.md5Hex("88888888", "UTF-8"));
|
||||
newUserPO.setNickName(Optional.ofNullable(userInfo).map(WechatDecryptedUserInfo::getNickName).orElse(null));
|
||||
newUserPO.setAvatarUrl(Optional.ofNullable(userInfo).map(WechatDecryptedUserInfo::getAvatarUrl).orElse(null));
|
||||
newUserPO.setRoleId(1);
|
||||
}else {
|
||||
newUserPO.setId(baseUserPO.getId());
|
||||
newUserPO.setWechatOpenid(openid);
|
||||
newUserPO.setNickName(Optional.ofNullable(userInfo).map(WechatDecryptedUserInfo::getNickName).orElse(null));
|
||||
newUserPO.setAvatarUrl(Optional.ofNullable(userInfo).map(WechatDecryptedUserInfo::getAvatarUrl).orElse(null));
|
||||
}
|
||||
baseUserRepo.saveOrUpdate(newUserPO);
|
||||
|
||||
return getLoginResponse(openid,MiniProgramTypeEnum.WECHAT.getType());
|
||||
}catch (Exception e){
|
||||
log.error("微信小程序注册失败", e);
|
||||
throw new BizException("微信小程序注册失败");
|
||||
}
|
||||
baseUserPO = new BaseUserPO();
|
||||
baseUserPO.setUserName(nickName);
|
||||
baseUserPO.setNickName(nickName);
|
||||
baseUserPO.setPhoneNumber(phoneNumber);
|
||||
baseUserPO.setPassword(MD5Utils.md5Hex("88888888", "UTF-8"));
|
||||
baseUserPO.setAvatarUrl(avatarUrl);
|
||||
baseUserPO.setRoleId(1);
|
||||
baseUserRepo.save(baseUserPO);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,15 +130,7 @@ public class UserServiceImpl implements IUserService {
|
||||
if (openid == null) {
|
||||
throw new BizException("无效的微信登录code");
|
||||
}
|
||||
// 模拟登录逻辑
|
||||
SimpleUserInfoDTO simpleUserInfoDTO = getUserInfoByProgramId(openid, MiniProgramTypeEnum.WECHAT.getType());
|
||||
|
||||
String token = jwtUtil.generateToken(simpleUserInfoDTO, simpleUserInfoDTO.getUserName());
|
||||
|
||||
LoginResponse loginResponse = new LoginResponse();
|
||||
loginResponse.setToken(token);
|
||||
loginResponse.setUserInfo(simpleUserInfoDTO);
|
||||
return loginResponse;
|
||||
return getLoginResponse(openid,MiniProgramTypeEnum.WECHAT.getType());
|
||||
}
|
||||
|
||||
|
||||
@ -133,4 +166,21 @@ public class UserServiceImpl implements IUserService {
|
||||
BaseUserPO baseUserPO = baseUserRepo.getOne(queryWrapper);
|
||||
return UserInfoConvert.INSTANCE.poToSimpleDTO(baseUserPO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录信息
|
||||
* @param programId
|
||||
* @param programType
|
||||
* @return
|
||||
*/
|
||||
private LoginResponse getLoginResponse(String programId, String programType) {
|
||||
SimpleUserInfoDTO simpleUserInfoDTO = getUserInfoByProgramId(programId, programType);
|
||||
|
||||
String token = jwtUtil.generateToken(simpleUserInfoDTO, simpleUserInfoDTO.getUserName());
|
||||
|
||||
LoginResponse loginResponse = new LoginResponse();
|
||||
loginResponse.setToken(token);
|
||||
loginResponse.setUserInfo(simpleUserInfoDTO);
|
||||
return loginResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package com.sczx.user.thirdpart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信解密手机信息
|
||||
*/
|
||||
@Data
|
||||
public class WechatDecryptedPhoneInfo {
|
||||
private String phoneNumber;
|
||||
private String purePhoneNumber;
|
||||
private String countryCode;
|
||||
private Watermark watermark;
|
||||
|
||||
@Data
|
||||
public static class Watermark {
|
||||
private String appid;
|
||||
private Long timestamp;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.sczx.user.thirdpart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WechatDecryptedUserInfo {
|
||||
private String nickName;
|
||||
private Integer gender;
|
||||
private String language;
|
||||
private String city;
|
||||
private String province;
|
||||
private String country;
|
||||
private String avatarUrl;
|
||||
private Watermark watermark;
|
||||
|
||||
@Data
|
||||
public static class Watermark {
|
||||
private String appid;
|
||||
private Long timestamp;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.sczx.user.thirdpart.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信小程序返回的加密数据
|
||||
*/
|
||||
@Data
|
||||
public class WechatEncryptedDataResponse {
|
||||
private String encryptedData;
|
||||
private String iv;
|
||||
private String signature;
|
||||
private String rawData;
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
package com.sczx.user.thirdpart.integ;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.sczx.user.exception.BizException;
|
||||
import com.sczx.user.thirdpart.dto.WechatDecryptedPhoneInfo;
|
||||
import com.sczx.user.thirdpart.dto.WechatDecryptedUserInfo;
|
||||
import com.sczx.user.thirdpart.dto.WechatMiniProgramResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -10,6 +13,10 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -42,7 +49,7 @@ public class WeichatInteg {
|
||||
return objectMapper.readValue(response, WechatMiniProgramResponse.class);
|
||||
} catch (Exception e) {
|
||||
log.error("获取微信session信息异常", e);
|
||||
return null;
|
||||
throw new BizException("获取微信session信息异常");
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,17 +61,95 @@ public class WeichatInteg {
|
||||
public String getWechatOpenIdByCode(String code) {
|
||||
WechatMiniProgramResponse response = getSessionInfoByCode(code);
|
||||
if (response == null) {
|
||||
return null;
|
||||
throw new BizException("获取微信openId信息异常");
|
||||
}
|
||||
|
||||
if (response.getErrcode() != null && response.getErrcode() != 0) {
|
||||
log.error("微信接口调用失败,错误码:{},错误信息:{}", response.getErrcode(), response.getErrmsg());
|
||||
return null;
|
||||
throw new BizException("获取微信openId信息异常");
|
||||
}
|
||||
|
||||
return response.getOpenid();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密微信加密数据
|
||||
* @param sessionKey 会话密钥
|
||||
* @param encryptedData 加密数据
|
||||
* @param iv 初始化向量
|
||||
* @return 解密后的数据字符串
|
||||
*/
|
||||
public String decryptWechatData(String sessionKey, String encryptedData, String iv) {
|
||||
try {
|
||||
byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
|
||||
byte[] encryptedDataBytes = Base64.getDecoder().decode(encryptedData);
|
||||
byte[] ivBytes = Base64.getDecoder().decode(iv);
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
||||
|
||||
byte[] result = cipher.doFinal(encryptedDataBytes);
|
||||
String resultStr = new String(result);
|
||||
|
||||
// 去除填充字符
|
||||
int paddingIndex = resultStr.indexOf("\0");
|
||||
if (paddingIndex > 0) {
|
||||
resultStr = resultStr.substring(0, paddingIndex);
|
||||
}
|
||||
|
||||
return resultStr;
|
||||
} catch (Exception e) {
|
||||
log.error("解密微信数据异常", e);
|
||||
throw new BizException("解密微信数据异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密手机号信息
|
||||
* @param sessionKey 会话密钥
|
||||
* @param encryptedData 加密的手机号数据
|
||||
* @param iv 初始化向量
|
||||
* @return 解密后的手机号信息
|
||||
*/
|
||||
public WechatDecryptedPhoneInfo decryptPhoneNumber(String sessionKey, String encryptedData, String iv) {
|
||||
try {
|
||||
String decryptedJson = decryptWechatData(sessionKey, encryptedData, iv);
|
||||
if (decryptedJson == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.readValue(decryptedJson, WechatDecryptedPhoneInfo.class);
|
||||
} catch (Exception e) {
|
||||
log.error("解密手机号信息异常", e);
|
||||
throw new BizException("解密手机号信息异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密用户信息(昵称、头像等)
|
||||
* @param sessionKey 会话密钥
|
||||
* @param encryptedData 加密的用户数据
|
||||
* @param iv 初始化向量
|
||||
* @return 解密后的用户信息
|
||||
*/
|
||||
public WechatDecryptedUserInfo decryptUserInfo(String sessionKey, String encryptedData, String iv) {
|
||||
try {
|
||||
String decryptedJson = decryptWechatData(sessionKey, encryptedData, iv);
|
||||
if (decryptedJson == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.readValue(decryptedJson, WechatDecryptedUserInfo.class);
|
||||
} catch (Exception e) {
|
||||
log.error("解密用户信息异常", e);
|
||||
throw new BizException("解密用户信息异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取访问令牌(用于调用其他微信接口)
|
||||
* @return access_token
|
||||
|
||||
Reference in New Issue
Block a user