微信支付分(五)--回调通知


1、介绍

代码地址: https://github.com/xm646236438/wechat_pay_score/tree/master
SpringBoot
具体的代码以及逻辑可以看 微信支付分(一)–创建支付分订单 以及 GitHub
上一篇博客: 微信支付分(四)–取消支付分订单

2、代码

public ResponseEntity payScoreCallbackNotification(HttpServletRequest request) {
    
    
        try {
    
    
            ServletInputStream servletInputStream = request.getInputStream();
            int contentLength = request.getContentLength();
            byte[] callBackInBytes = new byte[contentLength];
            servletInputStream.read(callBackInBytes, 0, contentLength);
            String callBackIn = new String(callBackInBytes, "UTF-8");
            // 模拟确认订单回调通知API
//            String callBackIn = "{\"id\":\"123\",\"create_time\":\"2020-11-02T16:31:35+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"PAYSCORE.USER_CONFIRM\",\"summary\":\"微信支付分服务订单用户已确认\",\"resource\":{\"original_type\":\"payscore\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"1111111111==\",\"associated_data\":\"payscore\",\"nonce\":\"12321321\"}}";
            // 模拟支付成功回调通知API
//            String callBackIn = "{\"id\":\"123\",\"create_time\":\"2020-11-02T16:31:35+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"PAYSCORE.USER_PAID\",\"summary\":\"微信支付分服务订单支付成功\",\"resource\":{\"original_type\":\"payscore\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"1111111111==\",\"associated_data\":\"payscore\",\"nonce\":\"12321321\"}}";

            log.info("【微信支付分免密支付回调】:" + callBackIn);


            JSONObject notifyIn = JSONObject.parseObject(callBackIn);
            if (notifyIn == null) {
    
    
                log.error("参数不正确,反序列化失败");
                return new ResponseEntity(HttpStatus.EXPECTATION_FAILED);
            }

            //解密回调信息
            JSONObject resource = notifyIn.getJSONObject("resource");
            byte[] key = (mchKeyVVV).getBytes("UTF-8");
            ApiV3Util aesUtil = new ApiV3Util(key);
            String decryptToString = aesUtil.decryptToString(resource.getString("associated_data").getBytes("UTF-8"), resource.getString("nonce").getBytes("UTF-8"), resource.getString("ciphertext"));

            if (StringUtils.isEmpty(decryptToString)) {
    
    
                return new ResponseEntity(HttpStatus.EXPECTATION_FAILED);
            }
            log.info("【支付分支付回调解密结果:】" + decryptToString);


            // 用户确认成功
            if ("PAYSCORE.USER_CONFIRM".equals(notifyIn.get("event_type"))) {
    
    
                log.info("用户确认成功");
                // 处理业务逻辑
            }
            // 支付成功
            if ("PAYSCORE.USER_PAID".equals(notifyIn.get("event_type"))) {
    
    
                log.info("用户支付成功");
                // 处理业务逻辑
            }
            return new ResponseEntity(HttpStatus.OK);
        } catch (Exception e) {
    
    
            log.error("微信支付回调处理异常," + e.toString());
            return new ResponseEntity(HttpStatus.EXPECTATION_FAILED);
        }
    }
package com.tomorrow.wechat_pay_score.util.wechart;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * @author Tomorrow
 * @date 2020/6/21 17:09
 */
public class ApiV3Util {
    
    
    static final int KEY_LENGTH_BYTE = 32;
    static final int TAG_LENGTH_BIT = 128;
    private final byte[] aesKey;


    public ApiV3Util(byte[] key) {
    
    
        if (key.length != KEY_LENGTH_BYTE) {
    
    
            throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
        }
        this.aesKey = key;
    }

    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
            throws GeneralSecurityException, IOException {
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);

            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
    
    
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
    
    
            throw new IllegalArgumentException(e);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

3、注意点

1、回调的地址需要是HTTPS, 域名, 不能是IP, IP会接受不到
2、确认订单回调通知API(用户确认授权后就会回调)
3、支付成功回调通知API(在调用完结支付分订单API后就会调)
4、因为关键信息有些多, 所以马赛克多了点
5、如果是多商户该如何解密: 1.轮询解密, 2.早创建订单的notify_url上面做操作, 进行Restfule风格, 列如: https://****/{orderNo}/test, 截取orderNo进行区分
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_38637558/article/details/109452822