Browse Source

微信绑定手机号

tall3
zhizhi wu 4 years ago
parent
commit
cfbd31f68c
  1. 1
      pom.xml
  2. 7
      signin/pom.xml
  3. 5
      signin/src/main/java/com/ccsens/signin/api/UserController.java
  4. 14
      signin/src/main/java/com/ccsens/signin/bean/dto/UserDto.java
  5. 4
      signin/src/main/java/com/ccsens/signin/service/IUserService.java
  6. 34
      signin/src/main/java/com/ccsens/signin/service/UserService.java
  7. 4
      signin/src/main/resources/application.yml
  8. 1
      util/src/main/java/com/ccsens/util/CodeEnum.java
  9. 2
      util/src/main/java/com/ccsens/util/WebConstant.java
  10. 15
      util/src/test/java/com/ccsens/util/Base64Test.java
  11. 2
      wechatutil/src/main/java/com/ccsens/wechatutil/api/DebugController.java
  12. 27
      wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/WxPhoneDecryptInfo.java
  13. 102
      wechatutil/src/main/java/com/ccsens/wechatutil/wxmini/MiniEncryptionAndDecryptionUtil.java

1
pom.xml

@ -20,6 +20,7 @@
<!--<module>tcm</module>-->
<module>signin</module>
<module>common</module>
<module>wechatutil</module>
<!-- <module>pims</module>-->
<!-- <module>health</module>-->

7
signin/pom.xml

@ -27,6 +27,13 @@
<version>1.0-SNAPSHOT</version>
</dependency>
<!--wechatUtil 工具类-->
<dependency>
<artifactId>wechatutil</artifactId>
<groupId>com.ccsens</groupId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>

5
signin/src/main/java/com/ccsens/signin/api/UserController.java

@ -222,8 +222,11 @@ public class UserController {
})
@RequestMapping(value="/bindingNoCode",method = RequestMethod.POST,produces = {"application/json;charset=UTF-8"})
public JsonResponse<UserVo.TokenBean> bindingPhoneNoCode(HttpServletRequest request,
@ApiParam @RequestBody UserDto.WxBindingPhone wxPhone) throws Exception {
@ApiParam @RequestBody UserDto.WxBindingPhone2 wxPhone) throws Exception {
Long currentUserId = Long.valueOf(((Claims) request.getAttribute(WebConstant.REQUEST_KEY_CLAIMS)).getSubject());
UserVo.UserSign userSignVo = userService.bindingPhoneNoCode(currentUserId,wxPhone);
UserVo.TokenBean tokenBean = null;

14
signin/src/main/java/com/ccsens/signin/bean/dto/UserDto.java

@ -142,6 +142,20 @@ public class UserDto {
private String smsCode;
}
@Data
@ApiModel
public static class WxBindingPhone2{
@NotEmpty
@ApiModelProperty("加密数据")
private String encryptedData;
@NotEmpty
@ApiModelProperty("iv")
private String iv;
@NotEmpty
@ApiModelProperty("小程序类型 tall:tall basicCar:暴风眼 SP:赛跑 SQ:数钱 BH:拔河")
private String miniType;
}
@Data
@ApiModel
public static class WxInfo{

4
signin/src/main/java/com/ccsens/signin/service/IUserService.java

@ -105,8 +105,8 @@ public interface IUserService {
/**
* 绑定手机号不用验证码
* @param currentUserId userId
* @param wxPhone 手机号
* @param wxPhone 加密数据
* @return
*/
UserVo.UserSign bindingPhoneNoCode(Long currentUserId, UserDto.WxBindingPhone wxPhone);
UserVo.UserSign bindingPhoneNoCode(Long currentUserId, UserDto.WxBindingPhone2 wxPhone);
}

34
signin/src/main/java/com/ccsens/signin/service/UserService.java

@ -24,6 +24,8 @@ import com.ccsens.util.enterprisewx.vo.WeiXinVo;
import com.ccsens.util.exception.BaseException;
import com.ccsens.util.wx.WxGzhUtil;
import com.ccsens.util.wx.WxXcxUtil;
import com.ccsens.wechatutil.bean.po.WxPhoneDecryptInfo;
import com.ccsens.wechatutil.wxmini.MiniEncryptionAndDecryptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;
@ -346,12 +348,18 @@ public class UserService implements IUserService {
//0.获取openid
Long start = System.currentTimeMillis();
WxXcxUtil.WechatUser wechatUser = WxXcxUtil.getUserInfo(code, gameType);
log.info("微信登录:{}", wechatUser);
Long end = System.currentTimeMillis();
log.info("调用微信查询openId耗时:{}", end - start);
String openId = wechatUser.openid;
String unionId = wechatUser.unionid;
log.info("小程序登录,openid:{} ,unionId:{}", openId, unionId);
return getUserSign(openId, unionId, (byte) WebConstant.IDENTIFY_TYPE.Wxmp.value, null);
UserVo.UserSign sign = getUserSign(openId, unionId, (byte) WebConstant.IDENTIFY_TYPE.Wxmp.value, null);
if (sign == null) {
return null;
}
redisUtil.set(StrUtil.format(WebConstant.Wx.SESSION_KEY, sign.getUserId(), gameType), wechatUser.session_key);
return sign;
}
@ -818,11 +826,11 @@ public class UserService implements IUserService {
* 绑定手机号不用验证码
*
* @param currentUserId userId
* @param wxPhone 手机号
* @param wxPhone 手机号加密
* @return 用户id和认证类型
*/
@Override
public UserVo.UserSign bindingPhoneNoCode(Long currentUserId, UserDto.WxBindingPhone wxPhone) {
public UserVo.UserSign bindingPhoneNoCode(Long currentUserId, UserDto.WxBindingPhone2 wxPhone) {
UserVo.UserSign userSignVo;
//查找该用户以前绑定的手机
SysAuthExample authExample = new SysAuthExample();
@ -832,11 +840,25 @@ public class UserService implements IUserService {
if (CollectionUtil.isNotEmpty(authList)) {
throw new BaseException(CodeEnum.ALREADY_BINDING_PHONE);
} else {
// 解密
Object sessionKey = redisUtil.get(StrUtil.format(WebConstant.Wx.SESSION_KEY, currentUserId, wxPhone.getMiniType()));
if (ObjectUtil.isNull(sessionKey)) {
throw new BaseException(CodeEnum.PARAM_ERROR);
}
String decryption = MiniEncryptionAndDecryptionUtil.decryption(wxPhone.getEncryptedData(), (String) sessionKey, wxPhone.getIv());
if (StrUtil.isEmpty(decryption)) {
throw new BaseException(CodeEnum.DATA_DECRYPTION);
}
WxPhoneDecryptInfo wxPhoneDecryptInfo = JSONObject.parseObject(decryption, WxPhoneDecryptInfo.class);
String phone = wxPhoneDecryptInfo.getPhoneNumber();
if (StrUtil.isEmpty(phone)) {
throw new BaseException(CodeEnum.WBS_NOT_PHONE);
}
//改手机对应账户,如果有,提示
List<SysAuth> phoneList;
SysAuthExample phoneExample = new SysAuthExample();
phoneExample.createCriteria().andIdentifyTypeEqualTo((byte) WebConstant.IDENTIFY_TYPE.Phone.value)
.andIdentifierEqualTo(wxPhone.getPhone());
.andIdentifierEqualTo(phone);
phoneList = authDao.selectByExample(phoneExample);
if (CollectionUtil.isNotEmpty(phoneList)) {
throw new BaseException(CodeEnum.MERGE_WX_PHONE);
@ -846,11 +868,11 @@ public class UserService implements IUserService {
auth.setId(snowflake.nextId());
auth.setUserId(currentUserId);
auth.setIdentifyType((byte) WebConstant.IDENTIFY_TYPE.Phone.value);
auth.setIdentifier(wxPhone.getPhone());
auth.setIdentifier(phone);
authDao.insertSelective(auth);
//给所有手机号一样的角色添加userId
relevanceUserService.relevancePhone(wxPhone.getPhone(), currentUserId);
relevanceUserService.relevancePhone(phone, currentUserId);
//返回值
userSignVo = new UserVo.UserSign();
userSignVo.setAuthId(auth.getId());

4
signin/src/main/resources/application.yml

@ -1,5 +1,5 @@
spring:
profiles:
active: dev
include: util-dev,common
active: prod
include: util-prod,common

1
util/src/main/java/com/ccsens/util/CodeEnum.java

@ -221,6 +221,7 @@ public enum CodeEnum {
//TALL3
PROJECT_REGION_NO_SAME(181,"项目域不同无法进行操作",true),
NO_POWER(182,"权限不足",true),
DATA_DECRYPTION(183,"解密失败,数据可能遭受到破坏,操作取消。",true),
;

2
util/src/main/java/com/ccsens/util/WebConstant.java

@ -46,6 +46,8 @@ public class WebConstant {
return String.format(GZH_AUTH_URL,appId, URLUtil.encode(url),wxGzhAuthType.getText());
}
public static final String SESSION_KEY = "{}_{}_session_key";
}
public enum WxGzhAuthType {

15
util/src/test/java/com/ccsens/util/Base64Test.java

@ -9,6 +9,7 @@ import com.alibaba.fastjson.JSONObject;
import com.ccsens.util.exception.BaseException;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.junit.Test;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
@ -18,6 +19,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @description:
@ -71,6 +73,19 @@ public class Base64Test {
throw new BaseException("ssss");
}
}
@Test
public void test04() throws NoSuchAlgorithmException {
String mingWen = "{\"nickName\":\"Band\",\"gender\":1,\"language\":\"zh_CN\",\"city\":\"Guangzhou\",\"province\":\"Guangdong\",\"country\":\"CN\",\"avatarUrl\":\"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0\"}HyVFkGl5F5OQWJZZaNzBBg==";
String sha1 = "75e81ceda165f4ffa64f4068af58c64b8f54b88c";
MessageDigest digest = MessageDigest.getInstance("SHA");
digest.update(mingWen.getBytes());
String result = Hex.encodeHexString(digest.digest());
System.out.println("==========" + (sha1.equals(result)));
}
/**

2
wechatutil/src/main/java/com/ccsens/wechatutil/api/DebugController.java

@ -60,7 +60,7 @@ public class DebugController {
})
@RequestMapping(value="message",method = RequestMethod.GET,produces = {"application/json;charset=UTF-8"})
public JsonResponse debugWxMessage(HttpServletRequest request) throws Exception {
OfficialAccountMessageUtil.officialMessage();
// OfficialAccountMessageUtil.officialMessage();
log.info("发送公众号消息");
return JsonResponse.newInstance().ok("测试");
}

27
wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/WxPhoneDecryptInfo.java

@ -0,0 +1,27 @@
package com.ccsens.wechatutil.bean.po;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @description:
* @author: whj
* @time: 2021/9/27 10:59
*/
@Data
public class WxPhoneDecryptInfo {
@ApiModelProperty("用户绑定的手机号(国外手机号会有区号)")
private String phoneNumber;
@ApiModelProperty("没有区号的手机号")
private String purePhoneNumber;
@ApiModelProperty("区号")
private int countryCode;
private WaterMark watermark;
@Data
public static class WaterMark {
/** 单位:秒 */
private Long timestamp;
private String appid;
}
}

102
wechatutil/src/main/java/com/ccsens/wechatutil/wxmini/MiniEncryptionAndDecryptionUtil.java

@ -0,0 +1,102 @@
package com.ccsens.wechatutil.wxmini;
import com.alibaba.fastjson.JSON;
import com.ccsens.wechatutil.bean.po.WxPhoneDecryptInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import org.apache.xmlbeans.impl.util.Base64;
/**
* @description:
* @author: whj
* @time: 2021/9/27 10:47
*/
@Slf4j
public class MiniEncryptionAndDecryptionUtil {
private final static String sha = "SHA";
/**加密方式*/
private final static String keyAlgorithm = "AES";
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* SHA1签名(获取手机号)
* @param data 原始数据
* @return 签名
* @throws
*/
public static String sha1(String data) {
log.info("签名原始数据:{}", data);
MessageDigest md;
try {
md = MessageDigest.getInstance(sha);
} catch (NoSuchAlgorithmException e) {
log.error("微信小程序签名异常:", e);
return null;
}
md.update(data.getBytes());
String result = Hex.encodeHexString(md.digest());
log.info("签名结果:{}", result);
return result;
}
/**
* 解密获取手机号
* @param originalContent 待解密数据
* @param sessionKey 会话密钥
* @param iv 加密算法的初始向量
* @return 解密数据
*/
public static String decryption(String originalContent, String sessionKey, String iv ){
try {
log.info("数据解密, original:{}, key:{}, iv:{}", originalContent, sessionKey, iv);
//数据填充方式
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(Base64.decode(sessionKey.getBytes()), keyAlgorithm);
// 初始化
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(Base64.decode(iv.getBytes())));
byte[]data = cipher.doFinal(Base64.decode(originalContent.getBytes()));
String result = new String(data, StandardCharsets.UTF_8);
log.info("微信小程序解密数据:{}", result);
return result;
} catch (Exception e) {
log.error("解密异常:", e);
return null;
}
}
/**
* 生成iv
* @param iv iv
* @return iv对象
* @throws NoSuchAlgorithmException 没有签名
* @throws InvalidParameterSpecException 无效参数
*/
private static AlgorithmParameters generateIV(byte[] iv) throws NoSuchAlgorithmException, InvalidParameterSpecException {
AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm);
params.init(new IvParameterSpec(iv));
return params;
}
public static void main(String[] args) {
String content = "aH7vLxzu3upsT8kK5DbjCbsIoOkTKIKUSNruHbhmmH6km/Yeb1eCsdfFY4HNPeNZH0oBRGmQ7sn8c/PaaYlLfi9598ghEvfl3HENWSLl43MqNXEFvCtTzxhc0Y7dJRtKCIWL4EEr8M42XxnhH77lAmpLomL+fbzw8upmz+gcJWqYMnXPKtGH2B2BeHC/njUgeuAeTqR7zuYihPyVY4Ol8g==";
String iv = "eW1+fg0f3TOU25MQfvTDwg==";
String sessionKey = "gA+NNouMd0FMmaf3LkQrMA==";
decryption(content, sessionKey, iv);
}
}
Loading…
Cancel
Save