Browse Source

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
LIVE_YE 1 year ago
parent
commit
d3b51b3e60

+ 4 - 3
ruoyi-admin/src/main/java/com/ruoyi/web/controller/alipay/AlipayTradeWapPayController.java

@@ -1,6 +1,7 @@
 package com.ruoyi.web.controller.alipay;
 package com.ruoyi.web.controller.alipay;
 
 
 import com.alibaba.fastjson2.JSONObject;
 import com.alibaba.fastjson2.JSONObject;
+import com.alipay.api.domain.AlipayTradeWapPayModel;
 import com.ruoyi.system.service.IAlipayService;
 import com.ruoyi.system.service.IAlipayService;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.Log;
@@ -24,14 +25,14 @@ public class AlipayTradeWapPayController {
     private IAlipayService alipayService;
     private IAlipayService alipayService;
 
 
     @ApiOperation("统一收单下单并支付接口调用")
     @ApiOperation("统一收单下单并支付接口调用")
-    @GetMapping("/scanPay")
-    public String tradePagePay() throws Exception {
+    @PostMapping("/scanPay")
+    public String tradePagePay(@RequestBody AlipayTradeWapPayModel model) throws Exception {
         System.out.println("统一收单下单并支付接口调用");
         System.out.println("统一收单下单并支付接口调用");
         /*
         /*
         支付宝开放平台接收 request 请求对象后
         支付宝开放平台接收 request 请求对象后
         会为开发者生成一个html形式的form表单,包含自动提交的脚本
         会为开发者生成一个html形式的form表单,包含自动提交的脚本
          */
          */
-        String formStr = alipayService.tradeCreate();
+        String formStr = alipayService.tradeCreate(model);
         /*
         /*
         将form表单字符串返回给前端
         将form表单字符串返回给前端
         前端自动提交脚本
         前端自动提交脚本

+ 0 - 6
ruoyi-admin/src/main/java/com/ruoyi/web/controller/sf/SfExpressController.java

@@ -7,21 +7,15 @@ import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.domain.sf.SfBean;
 import com.ruoyi.system.domain.sf.SfBean;
 import com.ruoyi.system.domain.sf.SfRespVo;
 import com.ruoyi.system.domain.sf.SfRespVo;
-import com.ruoyi.system.domain.wx.WxPayOrderReqVo;
 import com.sf.csim.express.service.CallExpressServiceTools;
 import com.sf.csim.express.service.CallExpressServiceTools;
 import com.sf.csim.express.service.HttpClientUtil;
 import com.sf.csim.express.service.HttpClientUtil;
 import com.sf.csim.express.service.IServiceCodeStandard;
 import com.sf.csim.express.service.IServiceCodeStandard;
 import com.sf.csim.express.service.code.ExpressServiceCodeEnum;
 import com.sf.csim.express.service.code.ExpressServiceCodeEnum;
-import io.swagger.annotations.ApiOperation;
-import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
-import springfox.documentation.spring.web.SpringfoxWebMvcConfiguration;
-
 import javax.annotation.Resource;
 import javax.annotation.Resource;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.UUID;
 import java.util.UUID;

+ 15 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/wx/WxPayController.java

@@ -2,6 +2,8 @@ package com.ruoyi.web.controller.wx;
 
 
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.wx.AppletLoginForm;
+import com.ruoyi.system.domain.wx.AppletSessionDTO;
 import com.ruoyi.system.domain.wx.WxPayOrderReqVo;
 import com.ruoyi.system.domain.wx.WxPayOrderReqVo;
 import com.ruoyi.system.domain.wx.WxPayRespVo;
 import com.ruoyi.system.domain.wx.WxPayRespVo;
 import com.ruoyi.system.service.ISysPostService;
 import com.ruoyi.system.service.ISysPostService;
@@ -9,10 +11,8 @@ import com.ruoyi.system.service.IWxPayService;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+import utils.WxCodeSessionUtil;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
@@ -42,4 +42,15 @@ public class WxPayController extends BaseController {
         wxPayService.payNotify(request);
         wxPayService.payNotify(request);
         return AjaxResult.success();
         return AjaxResult.success();
     }
     }
+
+    /**
+     * 小程序登录
+     * @param  form
+     * @return
+     */
+    @PostMapping("/jsCode")
+    public AjaxResult code2Session(@RequestBody AppletLoginForm form){
+        AppletSessionDTO appletSessionDTO = WxCodeSessionUtil.jscode2Session(form);
+        return AjaxResult.success(appletSessionDTO);
+    }
 }
 }

+ 1 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -105,7 +105,7 @@ ali:
   # 接口内容加密密钥 对此密钥
   # 接口内容加密密钥 对此密钥
    content-key: +ZyQ==
    content-key: +ZyQ==
   #页面跳转同步通知页面   测试地址  后期需要修改为实际地址
   #页面跳转同步通知页面   测试地址  后期需要修改为实际地址
-   return-url: https://www.baidu.com/
+   return-url: https://www.baidu.com/ali/pay/tradeNotify
 #顺风配置
 #顺风配置
 sf:
 sf:
   #此处替换为您在丰桥平台获取的顾客编码
   #此处替换为您在丰桥平台获取的顾客编码

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -112,7 +112,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .authorizeRequests()
                 .authorizeRequests()
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                 .antMatchers("/login", "/register", "/captchaImage").permitAll()
                 .antMatchers("/login", "/register", "/captchaImage").permitAll()
-                .antMatchers("/new/news/**", "/register", "/captchaImage","/china/area/fractionation/**").permitAll()
+                .antMatchers("/new/news/**", "/wx/pay/**", "/ali/pay/**","/sf/**").permitAll()
                 // 静态资源,可匿名访问
                 // 静态资源,可匿名访问
                 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                 .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                 .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

+ 55 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/wx/AppletLoginForm.java

@@ -0,0 +1,55 @@
+package com.ruoyi.system.domain.wx;
+
+import com.ruoyi.common.core.domain.entity.SysUser;
+
+/**
+ * @author shiqian
+ * @date 2021年09月08日 17:15
+ **/
+public class AppletLoginForm {
+
+
+    // 微信code
+    private String code;
+
+    // 微信用户基本信息
+    private SysUser user;
+
+    // 加密数据
+    private String encryptedData;
+
+    // 向量
+    private String iv;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public SysUser getUser() {
+        return user;
+    }
+
+    public void setUser(SysUser user) {
+        this.user = user;
+    }
+
+    public String getEncryptedData() {
+        return encryptedData;
+    }
+
+    public void setEncryptedData(String encryptedData) {
+        this.encryptedData = encryptedData;
+    }
+
+    public String getIv() {
+        return iv;
+    }
+
+    public void setIv(String iv) {
+        this.iv = iv;
+    }
+}

+ 53 - 0
ruoyi-system/src/main/java/com/ruoyi/system/domain/wx/AppletSessionDTO.java

@@ -0,0 +1,53 @@
+package com.ruoyi.system.domain.wx;
+
+
+/**
+ * 微信通用接口凭证
+ */
+
+public class AppletSessionDTO {
+
+    // 授权openid
+    private String openId;
+
+    // 微信会话session
+    private String sessionKey;
+
+    // 微信用户唯一unionid
+    private String unionId;
+
+    // 绑定手机号
+    private String phoneNumber;
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public String getSessionKey() {
+        return sessionKey;
+    }
+
+    public void setSessionKey(String sessionKey) {
+        this.sessionKey = sessionKey;
+    }
+
+    public String getUnionId() {
+        return unionId;
+    }
+
+    public void setUnionId(String unionId) {
+        this.unionId = unionId;
+    }
+
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    public void setPhoneNumber(String phoneNumber) {
+        this.phoneNumber = phoneNumber;
+    }
+}

+ 12 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/wx/WxPayV3Bean.java

@@ -26,6 +26,16 @@ public class WxPayV3Bean {
 
 
     private String keyPath;
     private String keyPath;
 
 
+    private String jscode2session;
+
+    public String getJscode2session() {
+        return jscode2session;
+    }
+
+    public void setJscode2session(String jscode2session) {
+        this.jscode2session = jscode2session;
+    }
+
     public String getAppId() {
     public String getAppId() {
         return appId;
         return appId;
     }
     }
@@ -84,7 +94,7 @@ public class WxPayV3Bean {
 
 
     @Override
     @Override
     public String toString() {
     public String toString() {
-        return "WxPayOrderReqVo{" +
+        return "WxPayV3Bean{" +
                 "appId='" + appId + '\'' +
                 "appId='" + appId + '\'' +
                 ", mchId='" + mchId + '\'' +
                 ", mchId='" + mchId + '\'' +
                 ", mchSerialNo='" + mchSerialNo + '\'' +
                 ", mchSerialNo='" + mchSerialNo + '\'' +
@@ -92,6 +102,7 @@ public class WxPayV3Bean {
                 ", apiKey='" + apiKey + '\'' +
                 ", apiKey='" + apiKey + '\'' +
                 ", notifyUrl='" + notifyUrl + '\'' +
                 ", notifyUrl='" + notifyUrl + '\'' +
                 ", keyPath='" + keyPath + '\'' +
                 ", keyPath='" + keyPath + '\'' +
+                ", jscode2session='" + jscode2session + '\'' +
                 '}';
                 '}';
     }
     }
 }
 }

+ 3 - 1
ruoyi-system/src/main/java/com/ruoyi/system/service/IAlipayService.java

@@ -1,5 +1,7 @@
 package com.ruoyi.system.service;
 package com.ruoyi.system.service;
 
 
+import com.alipay.api.domain.AlipayTradeWapPayModel;
+
 import java.util.Map;
 import java.util.Map;
 
 
 /**
 /**
@@ -12,7 +14,7 @@ public interface IAlipayService {
      * 支付宝开放平台接收 request请求对象后
      * 支付宝开放平台接收 request请求对象后
      * @return
      * @return
      */
      */
-    String tradeCreate() throws Exception;
+    String tradeCreate(AlipayTradeWapPayModel model) throws Exception;
 
 
     /**
     /**
      * 支付宝回调
      * 支付宝回调

+ 13 - 11
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/AlipayServiceImpl.java

@@ -27,30 +27,32 @@ public class AlipayServiceImpl implements IAlipayService {
      * @return
      * @return
      */
      */
     @Override
     @Override
-    public String tradeCreate() throws Exception {
-        String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdEgdHzKCYUjMUW9eNkVU6I6JWstTRCw5w6typSld7LKF0mCCnz0GFrxx4p+28rQzp8V9ONH/UH81qFSrQQIZPMdJQITNqJNidC7ypMcarruZhvmwa/9O1U/teKbelMuBtWoke0deAl6YmNXcc5t1EU2mYbwF3ITYBylxRpQ5Mea6ScERP0kxfyTGkQ8K1TdrvXHvr0HePbl2TDBCN88B/QwTx0wIL1cdBSriewftiZ+PITctYlXtPqtKe/WEWl4vk+pfLYDH/q6XkR4zrxXkHhyV0JHZSeO2FNsMdcv3zImbaWAHdbiQj5gaWywXaMdnOaYyFKSSKStbYnWue6HHLAgMBAAECggEAPqYeOUkpFRhUP16Sj2jUcagc7C/QKsEaNXe4I93/HqYij/rNq6FDJSs/U/DHJmZvrDAWL39JLTayHAntVbsm1xesJ0HW3BNuQtWXnnS4JWpRgdMOE4bOzph8voYtNbshQPzHjH9uUWAraToSFHkQ8FvE1oQQNZANlpE8WWRYW6/bftFEkVi+VeJUH8xEhFUkwuMZ5w7ERnMCjqnzdtBYLFA3pAJQkyv0XLEj5Bs/IetF4Q4+IopeI/H7+vFwRmDnZvNDdgWOyFnWsuvW1rhJjhYF/B56MWZwP/KfbZdI3YjMdYpveULzesk4wlG5xuzmFsS3AKw2nm/Rq/HtQmIRgQKBgQDoJnPwii3nmiO/FA35pkVNvGWSBtHheRnwhUvwqd1p68/sxNPe5LiBP8zwr1hTtUT+zy5TZQLF3HIlzARIH6NVEh5YTFK3OkJu18w64IrAEKCMfO3U2lYaDIDHrPqkMMFYKKyNJA6cUkCG5g3QXNuFXqUPUjOJjAFTrRqGyVE3mwKBgQCtNPpz8nux/y+X6ggRDdeI2bpr+BrMQKT1DF/an9k8twP1i0S+RBkCEoRlSJ6gELE24dA6ZuU9tnE0FO14eM2cUviqHU3pkyUj9rcpHxlYBokCyr8q5EnTruYsAzoydcc99CiHD3QC2LDdFb5iGh+OGn+Gql5S2T6A5nO4zNKJkQKBgQDKvgJVGSg78way8n2+AHLYD+eYnzIeutdnkdIfbQn8XkApZEAwkgl8f06pCEmYWV/XNPMdS8MfL4XU8pbusgq/2eH8dTNr54prKTWoWb9zO1IrP1Opp8C4YSD6wVvnltjT+DmxzcKgzMijxzhbNy1UDbMTbVOrFUV3YV8gRaMTbwKBgBUfOMua7mqua+diqskpnvcZVhqEjwAJghRABhBrHdrBlsIC0cdCFqqiB3Myf+WVI4dF0lbM5Xe5H+TyCGOAl9JQa/KS0EWDpCvWkk95c2XApkSo5NceL8KYuYj0e8xbgIiVlbuirssKEcdkN2tPNDnoEVUiwY3o4C5n7ATFNYeBAoGBAKrFwAfpj70UC1jRmYJ/FL7h5M+CPIkweT+biD5YGC0T9ijrgKUm2LV1rCQyo70nGDP7/wK15XiuOk69oZCF/bdjNTpNpYA1j1sC1oHuq746zh/4protfOdb+mk6rVWwYF++swttQ5pcmu2W/l+ufd8edbkzMl/a2zi0kvVrnx2x";
-        String alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAogc/9hKx6FAM6btKymkkFh932UfOPal4DgxXGstpFUG5Ehc+dMqm6e0CoMfNjZ4IBTRttE/OaBP/mW+YI53Tb+ND2rb22BqG+5JMp1WBJ4Tdz6DTKsbTRfN0Hrv1HiBglpgaJZs6Oymt1b43jnpL1bWsUULBnI+PWamlIottHK2IHC3/d5jN/9gz6TP6VkPnmokiBr0Hfcmv7jMjWsVsOf1wh5Jk/I7VSc+H314EO83Z1Cd+jS7lXLhHz105ORKUQf0dZD0VBa9Nl1aOMGZThrpcA9S6B3KfE8f66fIFLkhG/7IM7zSSsR0G8aLxiORCN9vpf38qwxBrWuugJtJqqwIDAQAB";
+    public String tradeCreate(AlipayTradeWapPayModel model) throws Exception {
         //封装签名过程
         //封装签名过程
         AlipayConfig alipayConfig = new AlipayConfig();
         AlipayConfig alipayConfig = new AlipayConfig();
-        alipayConfig.setServerUrl("https://openapi-sandbox.dl.alipaydev.com/gateway.do");
-        alipayConfig.setAppId("9021000134610854");
-        alipayConfig.setPrivateKey(privateKey);
+        alipayConfig.setServerUrl(aliPayBean.getGatewayUrl());
+        alipayConfig.setAppId(aliPayBean.getAppId());
+        alipayConfig.setPrivateKey(aliPayBean.getMerchantPrivateKey());
         alipayConfig.setFormat("json");
         alipayConfig.setFormat("json");
-        alipayConfig.setAlipayPublicKey(alipayPublicKey);
+        alipayConfig.setAlipayPublicKey(aliPayBean.getPublicKey());
         alipayConfig.setCharset("UTF-8");
         alipayConfig.setCharset("UTF-8");
         alipayConfig.setSignType("RSA2");
         alipayConfig.setSignType("RSA2");
         AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
         AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
         ////支付宝公共参数
         ////支付宝公共参数
         AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
         AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
         ///同步跳转地址,仅支持http/https
         ///同步跳转地址,仅支持http/https
-        request.setReturnUrl("");
+        request.setReturnUrl(aliPayBean.getReturnUrl());
         //封装参数
         //封装参数
-        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
-        model.setOutTradeNo("70501111111S001111119");
+        /*产品码。 商家和支付宝签约的产品码。 枚举值(点击查看签约情况):
+         QUICK_WAP_WAY:手机网站支付产品。 默认值为 QUICK_WAP_WAY。*/
+        model.setProductCode("QUICK_WAP_WAY");
+        model.setOutTradeNo("DMGT"+System.currentTimeMillis());
+        //商户订单号。 由商家自定义,64个字符以内,仅支持字母、数字、下划线且需保证在商户端不重复。
+/*        model.setOutTradeNo("70501111111S001111119");
         model.setTotalAmount("9.00");
         model.setTotalAmount("9.00");
         model.setSubject("大乐透");
         model.setSubject("大乐透");
         model.setProductCode("QUICK_WAP_WAY");
         model.setProductCode("QUICK_WAP_WAY");
-        model.setSellerId("2088102147948060");
+        model.setSellerId("2088102147948060");*/
         request.setBizModel(model);
         request.setBizModel(model);
 
 
         //执行请求,调用支付宝
         //执行请求,调用支付宝

+ 20 - 3
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WxPayServiceImpl.java

@@ -65,13 +65,14 @@ public class WxPayServiceImpl implements IWxPayService {
             // request.setXxx(val)设置所需参数,具体参数可见Request定义
             // request.setXxx(val)设置所需参数,具体参数可见Request定义
             PrepayRequest request = new PrepayRequest();
             PrepayRequest request = new PrepayRequest();
             Amount amount = new Amount();
             Amount amount = new Amount();
-            amount.setTotal(req.getTotalPrice());
+            //元转分
+            amount.setTotal(req.getTotalPrice()*100);
             request.setAmount(amount);
             request.setAmount(amount);
             request.setAppid(wxPayV3Bean.getAppId());
             request.setAppid(wxPayV3Bean.getAppId());
             request.setMchid(wxPayV3Bean.getMchId());
             request.setMchid(wxPayV3Bean.getMchId());
             request.setDescription(req.getGoodsName());
             request.setDescription(req.getGoodsName());
             request.setNotifyUrl(wxPayV3Bean.getNotifyUrl());
             request.setNotifyUrl(wxPayV3Bean.getNotifyUrl());
-            request.setOutTradeNo(req.getOrderSn().toString());
+            request.setOutTradeNo("DMGT"+System.currentTimeMillis());
             request.setAttach(req.getOrderType());
             request.setAttach(req.getOrderType());
             Payer payer = new Payer();
             Payer payer = new Payer();
             payer.setOpenid(req.getOpenId());
             payer.setOpenid(req.getOpenId());
@@ -87,7 +88,7 @@ public class WxPayServiceImpl implements IWxPayService {
                     .collect(Collectors.joining("\n", "", "\n"));
                     .collect(Collectors.joining("\n", "", "\n"));
             String sign = WxPayUtil.getSign(signatureStr, wxPayV3Bean.getKeyPath());
             String sign = WxPayUtil.getSign(signatureStr, wxPayV3Bean.getKeyPath());
             vo.setPaySign(sign);
             vo.setPaySign(sign);
-            vo.setPrepayId("prepay_id=" + response.getPrepayId());
+            vo.setPrepayId(response.getPrepayId());
             //todo 存储预支付订单信息
             //todo 存储预支付订单信息
             return AjaxResult.success(vo);
             return AjaxResult.success(vo);
         }catch (ServiceException e){
         }catch (ServiceException e){
@@ -104,6 +105,22 @@ public class WxPayServiceImpl implements IWxPayService {
      */
      */
     @Override
     @Override
     public void payNotify(HttpServletRequest request) {
     public void payNotify(HttpServletRequest request) {
+        /**
+         * {
+         *     "id": "EV-2018022511223320873",
+         *     "create_time": "2015-05-20T13:29:35+08:00",
+         *     "resource_type": "encrypt-resource",
+         *     "event_type": "TRANSACTION.SUCCESS",
+         *     "summary": "支付成功",
+         *     "resource": {
+         *         "original_type": "transaction",
+         *         "algorithm": "AEAD_AES_256_GCM",
+         *         "ciphertext": "",
+         *         "associated_data": "",
+         *         "nonce": ""
+         *     }
+         * }
+         */
         try {
         try {
             //读取请求体的信息
             //读取请求体的信息
             ServletInputStream inputStream = request.getInputStream();
             ServletInputStream inputStream = request.getInputStream();

+ 58 - 0
ruoyi-system/src/main/java/utils/AppletDecryptDataUtil.java

@@ -0,0 +1,58 @@
+package utils;
+
+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.Security;
+import java.util.Arrays;
+
+/**
+ * 解密工具
+ */
+public class AppletDecryptDataUtil {
+
+    public static JSONObject decryptData(byte[] keyByte, byte[] ivByte, byte[] dataByte) throws Exception {
+        // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
+        int base = 16;
+        if (keyByte.length % base != 0) {
+            int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
+            byte[] temp = new byte[groups * base];
+            Arrays.fill(temp, (byte) 0);
+            System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
+            keyByte = temp;
+        }
+
+        byte[] resultByte;
+        // 初始化
+        Security.addProvider(new BouncyCastleProvider());
+        try {
+            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
+            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
+            parameters.init(new IvParameterSpec(ivByte));
+            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
+            resultByte = cipher.doFinal(dataByte);
+            if (null == resultByte || resultByte.length <= 0) {
+                return null;
+            }
+        }catch (Exception e){
+            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC");
+            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
+            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
+            parameters.init(new IvParameterSpec(ivByte));
+            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
+            resultByte = cipher.doFinal(dataByte);
+            if (null == resultByte || resultByte.length <= 0) {
+                return null;
+            }
+        }
+
+        String result = new String(resultByte, StandardCharsets.UTF_8);
+        return JSONObject.parseObject(result);
+    }
+}

+ 95 - 0
ruoyi-system/src/main/java/utils/HttpClientUtils.java

@@ -0,0 +1,95 @@
+package utils;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class HttpClientUtils {
+
+
+    final static int TIMEOUT_MSEC = 5 * 1000;
+
+    /**
+     * post 表单请求
+     * @param url
+     * @param paramMap
+     * @return
+     * @throws IOException
+     */
+    public static String doPost(String url, Map<String, String> paramMap) throws IOException {
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http Post请求
+            HttpPost httpPost = new HttpPost(url);
+            // 创建参数列表
+            if (paramMap != null) {
+                List<NameValuePair> paramList = new ArrayList<>();
+                for (Map.Entry<String, String> param : paramMap.entrySet()) {
+                    paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
+                }
+                // 模拟表单
+                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
+                httpPost.setEntity(entity);
+            }
+
+            httpPost.setConfig(builderRequestConfig());
+
+            // 执行http请求
+            response = httpClient.execute(httpPost);
+
+            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            try {
+                response.close();
+            } catch (IOException e) {
+                throw e;
+            }
+        }
+
+        return resultString;
+    }
+
+    public static String doGet(String url) throws IOException {
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http Post请求
+            HttpGet httpGet = new HttpGet(url);
+            // 执行http请求
+            response = httpClient.execute(httpGet);
+            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            assert response != null;
+            response.close();
+        }
+        return resultString;
+    }
+
+    private static RequestConfig builderRequestConfig() {
+        return RequestConfig.custom()
+                .setConnectTimeout(TIMEOUT_MSEC)
+                .setConnectionRequestTimeout(TIMEOUT_MSEC)
+                .setSocketTimeout(TIMEOUT_MSEC).build();
+    }
+}

+ 106 - 0
ruoyi-system/src/main/java/utils/WxCodeSessionUtil.java

@@ -0,0 +1,106 @@
+package utils;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.utils.sign.Base64;
+import com.ruoyi.system.domain.wx.AppletLoginForm;
+import com.ruoyi.system.domain.wx.AppletSessionDTO;
+import com.ruoyi.system.domain.wx.WxPayV3Bean;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.annotation.Resource;
+
+/**
+ *小程序工具类
+ */
+public class WxCodeSessionUtil {
+
+    private static final String JSCODE_SESSION_API = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";
+
+    /**
+     * 小程序appId
+     */
+    @Value("${wx.appId}")
+    private static String appId;
+
+    /**
+     * 小程序密钥
+     */
+    @Value("${wx.appSecret}")
+    private static String appSecret;
+    /**
+     * 根据code获取小程序openid和unionid
+     *
+     * @param form
+     * @return
+     */
+    public static AppletSessionDTO jscode2Session(AppletLoginForm form) {
+        // 获取openId和sessionKey
+        JSONObject result;
+        try {
+            String requestUrl = JSCODE_SESSION_API.replace("APPID", appId)
+                    .replace("SECRET", appSecret)
+                    .replace("JSCODE", form.getCode().trim());
+
+            String jsonStr = HttpClientUtils.doGet(requestUrl);
+            result = JSONObject.parseObject(jsonStr);
+            if (StringUtils.isEmpty(result.toString())) {
+                throw new RuntimeException("错误");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException("错误");
+        }
+
+        int errcode = result.getIntValue("errcode");
+        if (errcode != 0) {
+            String errmsg = result.getString("errmsg");
+            throw new RuntimeException("获取小程序授权错误信息, " + errmsg);
+        }
+        // 获取openId,unionId,sessionKey
+        AppletSessionDTO appletSession = new AppletSessionDTO();
+        appletSession.setOpenId(result.getString("openid"));
+        // unionId有可能是空
+        appletSession.setUnionId(result.getString("unionid"));
+        appletSession.setSessionKey(result.getString("session_key"));
+
+        System.out.println();
+        String phoneNumber = getPhoneNumber(form, appletSession);
+        appletSession.setPhoneNumber(phoneNumber);
+        return appletSession;
+    }
+
+    /**
+     * 手机号解密
+     */
+    private static String getPhoneNumber(AppletLoginForm form, AppletSessionDTO appletSession) {
+
+        // 解密文件
+        String encryptedData = form.getEncryptedData();
+        // 解密向量
+        String iv = form.getIv();
+        // 加密秘钥
+        byte[] dataByte = Base64.decode(encryptedData);
+        // session_key
+        byte[] keyByte = Base64.decode(appletSession.getSessionKey());
+        // 偏移量
+        byte[] ivByte = Base64.decode(iv);
+        JSONObject result;
+        try {
+            result = AppletDecryptDataUtil.decryptData(keyByte, ivByte, dataByte);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+
+        assert result != null;
+        String purePhoneNumber = result.getString("purePhoneNumber");
+        if (null == purePhoneNumber || purePhoneNumber.isEmpty()) {
+            throw new RuntimeException("获取手机号失败");
+        }
+        return purePhoneNumber;
+    }
+
+
+}