diff --git a/pom.xml b/pom.xml
index 7a58dae1..53c70268 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,6 +20,7 @@
signin
common
+ wechatutil
diff --git a/signin/pom.xml b/signin/pom.xml
index 392f33fd..db5fc614 100644
--- a/signin/pom.xml
+++ b/signin/pom.xml
@@ -27,6 +27,13 @@
1.0-SNAPSHOT
+
+
+ wechatutil
+ com.ccsens
+ 1.0-SNAPSHOT
+
+
diff --git a/signin/src/main/java/com/ccsens/signin/api/UserController.java b/signin/src/main/java/com/ccsens/signin/api/UserController.java
index 422c7428..ce62e0c0 100644
--- a/signin/src/main/java/com/ccsens/signin/api/UserController.java
+++ b/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 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;
diff --git a/signin/src/main/java/com/ccsens/signin/bean/dto/UserDto.java b/signin/src/main/java/com/ccsens/signin/bean/dto/UserDto.java
index 2eb199cf..26ff2525 100644
--- a/signin/src/main/java/com/ccsens/signin/bean/dto/UserDto.java
+++ b/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{
diff --git a/signin/src/main/java/com/ccsens/signin/service/IUserService.java b/signin/src/main/java/com/ccsens/signin/service/IUserService.java
index 95ee5eb8..81676015 100644
--- a/signin/src/main/java/com/ccsens/signin/service/IUserService.java
+++ b/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);
}
diff --git a/signin/src/main/java/com/ccsens/signin/service/UserService.java b/signin/src/main/java/com/ccsens/signin/service/UserService.java
index febab0ba..125aa4e8 100644
--- a/signin/src/main/java/com/ccsens/signin/service/UserService.java
+++ b/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 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());
diff --git a/signin/src/main/resources/application.yml b/signin/src/main/resources/application.yml
index b5408a3a..e75cc2c3 100644
--- a/signin/src/main/resources/application.yml
+++ b/signin/src/main/resources/application.yml
@@ -1,5 +1,5 @@
spring:
profiles:
- active: dev
- include: util-dev,common
+ active: prod
+ include: util-prod,common
diff --git a/util/src/main/java/com/ccsens/util/CodeEnum.java b/util/src/main/java/com/ccsens/util/CodeEnum.java
index 6b765978..5135524c 100644
--- a/util/src/main/java/com/ccsens/util/CodeEnum.java
+++ b/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),
;
diff --git a/util/src/main/java/com/ccsens/util/WebConstant.java b/util/src/main/java/com/ccsens/util/WebConstant.java
index e6899733..c3efbef0 100644
--- a/util/src/main/java/com/ccsens/util/WebConstant.java
+++ b/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 {
diff --git a/util/src/test/java/com/ccsens/util/Base64Test.java b/util/src/test/java/com/ccsens/util/Base64Test.java
index 522082c2..137e7ecb 100644
--- a/util/src/test/java/com/ccsens/util/Base64Test.java
+++ b/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)));
+
+
+
}
/**
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/api/DebugController.java b/wechatutil/src/main/java/com/ccsens/wechatutil/api/DebugController.java
index 9672c3c4..edeaa8af 100644
--- a/wechatutil/src/main/java/com/ccsens/wechatutil/api/DebugController.java
+++ b/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("测试");
}
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/WxPhoneDecryptInfo.java b/wechatutil/src/main/java/com/ccsens/wechatutil/bean/po/WxPhoneDecryptInfo.java
new file mode 100644
index 00000000..005a535d
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/wechatutil/src/main/java/com/ccsens/wechatutil/wxmini/MiniEncryptionAndDecryptionUtil.java b/wechatutil/src/main/java/com/ccsens/wechatutil/wxmini/MiniEncryptionAndDecryptionUtil.java
new file mode 100644
index 00000000..bc250191
--- /dev/null
+++ b/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);
+
+ }
+
+}