From b78b51d384a3c4d9880ba604ebe35f40de8c527f Mon Sep 17 00:00:00 2001 From: sjm <1191068887@qq.com> Date: Thu, 10 Aug 2023 19:02:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/core/config/H5MemberInterceptor.java | 1 + .../ruoyi/common/utils/AesCryptoUtils.java | 2 + ruoyi-mall/pom.xml | 5 ++ .../config/AESForWeixinGetPhoneNumber.java | 80 +++++++++++++++++++ .../cyl/h5/controller/H5MemberController.java | 17 +++- .../java/com/cyl/h5/pojo/dto/H5LoginDTO.java | 12 +++ .../com/cyl/h5/service/H5MemberService.java | 55 +++++++++++++ .../com/cyl/h5/service/H5OrderService.java | 2 +- 8 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 ruoyi-mall/src/main/java/com/cyl/config/AESForWeixinGetPhoneNumber.java create mode 100644 ruoyi-mall/src/main/java/com/cyl/h5/pojo/dto/H5LoginDTO.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/H5MemberInterceptor.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/H5MemberInterceptor.java index 6759cb6..8cbe353 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/H5MemberInterceptor.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/H5MemberInterceptor.java @@ -25,6 +25,7 @@ public class H5MemberInterceptor extends HandlerInterceptorAdapter { private static String[] WHITE_PATHS = { "/h5/sms/login", + "/h5/wechat/login", "/h5/account/login", "/h5/register", "/h5/validate" diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesCryptoUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesCryptoUtils.java index e509e42..e908fd3 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesCryptoUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/AesCryptoUtils.java @@ -10,6 +10,7 @@ import cn.hutool.crypto.symmetric.AES; public class AesCryptoUtils { public static String encrypt(String key, String content){ + SecureUtil.disableBouncyCastle(); if (StringUtils.isBlank(key) || StringUtils.isBlank(content)){ throw new RuntimeException("错误"); } @@ -19,6 +20,7 @@ public class AesCryptoUtils { } public static String decrypt(String key, String content){ + SecureUtil.disableBouncyCastle(); if (StringUtils.isBlank(key) || StringUtils.isBlank(content)){ throw new RuntimeException("错误"); } diff --git a/ruoyi-mall/pom.xml b/ruoyi-mall/pom.xml index 30f6a37..1f10156 100644 --- a/ruoyi-mall/pom.xml +++ b/ruoyi-mall/pom.xml @@ -62,6 +62,11 @@ junit test + + org.bouncycastle + bcprov-jdk15to18 + 1.64 + org.springframework spring-test diff --git a/ruoyi-mall/src/main/java/com/cyl/config/AESForWeixinGetPhoneNumber.java b/ruoyi-mall/src/main/java/com/cyl/config/AESForWeixinGetPhoneNumber.java new file mode 100644 index 0000000..0d308a0 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/config/AESForWeixinGetPhoneNumber.java @@ -0,0 +1,80 @@ +package com.cyl.config; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +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.AlgorithmParameters; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.security.spec.InvalidParameterSpecException; +import java.util.Base64; + +public class AESForWeixinGetPhoneNumber { + //加密方式 + private static String keyAlgorithm = "AES"; + //避免重复new生成多个BouncyCastleProvider对象,因为GC回收不了,会造成内存溢出 + //只在第一次调用decrypt()方法时才new 对象 + private static boolean initialized = false; + //用于Base64解密 + private Base64.Decoder decoder = Base64.getDecoder(); + + //待解密的数据 + private String originalContent; + //会话密钥sessionKey + private String encryptKey; + //加密算法的初始向量 + private String iv; + + public AESForWeixinGetPhoneNumber(String originalContent, String encryptKey, String iv) { + this.originalContent = originalContent; + this.encryptKey = encryptKey; + this.iv = iv; + } + + /** + * AES解密 + * 填充模式AES/CBC/PKCS7Padding + * 解密模式128 + * + * @return 解密后的信息对象 + */ + public JSONObject decrypt() { + initialize(); + try { + //数据填充方式 + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC"); +// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); + Key sKeySpec = new SecretKeySpec(decoder.decode(this.encryptKey), keyAlgorithm); + // 初始化 + cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(decoder.decode(this.iv))); + byte[]data = cipher.doFinal(decoder.decode(this.originalContent)); + String datastr = new String(data, StandardCharsets.UTF_8); + return JSON.parseObject(datastr); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /**BouncyCastle作为安全提供,防止我们加密解密时候因为jdk内置的不支持改模式运行报错。**/ + private static void initialize() { + if (initialized) { + return; + } + Security.addProvider(new BouncyCastleProvider()); + initialized = true; + } + + // 生成iv + private static AlgorithmParameters generateIV(byte[] iv) throws NoSuchAlgorithmException, InvalidParameterSpecException { + AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm); + params.init(new IvParameterSpec(iv)); + return params; + } +} diff --git a/ruoyi-mall/src/main/java/com/cyl/h5/controller/H5MemberController.java b/ruoyi-mall/src/main/java/com/cyl/h5/controller/H5MemberController.java index 46f17a6..cb4d62f 100644 --- a/ruoyi-mall/src/main/java/com/cyl/h5/controller/H5MemberController.java +++ b/ruoyi-mall/src/main/java/com/cyl/h5/controller/H5MemberController.java @@ -1,20 +1,20 @@ package com.cyl.h5.controller; +import com.alibaba.fastjson.JSON; +import com.cyl.h5.pojo.dto.H5LoginDTO; import com.cyl.h5.pojo.request.RegisterRequest; import com.cyl.h5.pojo.response.RegisterResponse; import com.cyl.h5.pojo.response.ValidatePhoneResponse; import com.cyl.h5.pojo.response.H5LoginResponse; import com.cyl.h5.service.H5MemberService; import com.cyl.manager.ums.pojo.vo.MemberVO; -import com.cyl.wechat.WechatAuthService; -import com.cyl.wechat.response.WechatUserAuth; -import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.domain.model.LoginMember; -import com.ruoyi.common.enums.BusinessType; import com.ruoyi.framework.web.service.TokenService; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; @@ -47,6 +47,15 @@ public class H5MemberController { return ResponseEntity.ok(service.accountLogin(data)); } + @PostMapping("/wechat/login") + public ResponseEntity wechatLogin(String data) throws Exception { + if (StringUtils.isEmpty(data)) { + return ResponseEntity.ok(null); + } + H5LoginDTO params = JSON.parseObject(new String(Base64Utils.decodeFromString(data)), H5LoginDTO.class); + return ResponseEntity.ok(service.wechatLogin(params)); + } + @ApiOperation("sms登录") @PostMapping("/sms/login") public ResponseEntity smsLogin(@RequestBody String data){ diff --git a/ruoyi-mall/src/main/java/com/cyl/h5/pojo/dto/H5LoginDTO.java b/ruoyi-mall/src/main/java/com/cyl/h5/pojo/dto/H5LoginDTO.java new file mode 100644 index 0000000..74d4977 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/h5/pojo/dto/H5LoginDTO.java @@ -0,0 +1,12 @@ +package com.cyl.h5.pojo.dto; + +import lombok.Data; + +@Data +public class H5LoginDTO { + + private String data; + private String key; + private String sessionKey; + private String openId; +} diff --git a/ruoyi-mall/src/main/java/com/cyl/h5/service/H5MemberService.java b/ruoyi-mall/src/main/java/com/cyl/h5/service/H5MemberService.java index 49ba446..89acf2c 100644 --- a/ruoyi-mall/src/main/java/com/cyl/h5/service/H5MemberService.java +++ b/ruoyi-mall/src/main/java/com/cyl/h5/service/H5MemberService.java @@ -3,8 +3,11 @@ package com.cyl.h5.service; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.cyl.config.AESForWeixinGetPhoneNumber; +import com.cyl.h5.pojo.dto.H5LoginDTO; import com.cyl.h5.pojo.request.BindOpenIdRequest; import com.cyl.h5.pojo.request.H5AccountLoginRequest; import com.cyl.h5.pojo.request.H5SmsLoginRequest; @@ -329,4 +332,56 @@ public class H5MemberService { memberLogininfor.setLoginTime(LocalDateTime.now()); memberLogininforMapper.insert(memberLogininfor); } + + public H5LoginResponse wechatLogin(H5LoginDTO params) throws Exception { + String openId = params.getOpenId(); + String sessionKey = params.getSessionKey(); + //解密手机号 + String mobile = getMobile(sessionKey, params.getKey(), params.getData()); + if(StringUtils.isEmpty(mobile)) { + throw new Exception("登录异常"); + } + Member member = createOrUpdateMember(openId,mobile); + return getLoginResponse(member.getId()); + } + + private Member createOrUpdateMember(String openId,String mobile){ + //查会员 + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("phone_encrypted", AesCryptoUtils.encrypt(aesKey, mobile)); + Member member = memberMapper.selectOne(qw); + if (member == null){ + //新会员,注册并登录 + member = new Member(); + member.setPhoneEncrypted(AesCryptoUtils.encrypt(aesKey, mobile)); + member.setPhoneHidden(PhoneUtils.hidePhone(mobile)); + member.setNickname("用户" + mobile.substring(7,11)); + member.setStatus(Constants.MEMBER_ACCOUNT_STATUS.NORMAL); + member.setGender(0); + member.setCreateTime(LocalDateTime.now()); + int rows = memberMapper.insert(member); + if (rows < 1){ + throw new RuntimeException("注册失败,请重试"); + } + MemberWechat memberWechat = new MemberWechat(); + memberWechat.setMemberId(member.getId()); + memberWechat.setRoutineOpenid(openId); + memberWechat.setCreateTime(LocalDateTime.now()); + memberWechat.setCreateBy(member.getId()); + rows = memberWechatMapper.insert(memberWechat); + if (rows < 1){ + throw new RuntimeException("注册失败,请重试"); + } + } + return member; + } + + private String getMobile(String sessionKey, String key, String data) { + AESForWeixinGetPhoneNumber aes = new AESForWeixinGetPhoneNumber(data, sessionKey, key); + JSONObject decrypt = aes.decrypt(); + if (decrypt != null) { + return decrypt.getString("phoneNumber"); + } + return null; + } } diff --git a/ruoyi-mall/src/main/java/com/cyl/h5/service/H5OrderService.java b/ruoyi-mall/src/main/java/com/cyl/h5/service/H5OrderService.java index 6bc5c8d..596ae77 100644 --- a/ruoyi-mall/src/main/java/com/cyl/h5/service/H5OrderService.java +++ b/ruoyi-mall/src/main/java/com/cyl/h5/service/H5OrderService.java @@ -472,7 +472,7 @@ public class H5OrderService { //保存微信支付历史 LocalDateTime optDate = LocalDateTime.now(); QueryWrapper wxPaymentQw = new QueryWrapper<>(); - wxPaymentQw.eq("order_id", orderList.get(0).getId()); + wxPaymentQw.eq("order_id", orderList.get(0).getPayId()); wxPaymentQw.eq("op_type", Constants.PaymentOpType.PAY); WechatPaymentHistory wechatPaymentHistory = wechatPaymentHistoryMapper.selectOne(wxPaymentQw); if (wechatPaymentHistory == null){