SpringBoot整合微信支付之扫码支付(Native支付)

微信支付没有沙箱环境,所以前期准备为必须

  • 必须是企业或者个体工商户认证通过的才能开通微信支付
  • 微信支付回调地址必须是公网可以访问的地址(http/https,建议https,阿里云有免费的证书)

    请求头签名工具

    WeChatAuthenorization
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    public class WeChatAuthenorization {

    private static final Logger logger = LoggerFactory.getLogger(WeChatAuthenorization.class);
    /**
    * method=========请求方式
    * path===========请求路径
    * paramMap=======请求体参数
    * apiclientKey===秘钥
    * mchid==========直连商户号
    * serialNO=======证书序列号
    * @param map
    * @return
    */
    public static String authenorization(Map<String, String> map) {
    String nonceStr = WeChatConstant.generateNonceStr();
    String timeStamp = WeChatConstant.getCurrentTimestamp();

    logger.info("签名参数:{}", map);
    String signAuthorizationStr = new StringBuffer()
    .append(map.get("method")).append("\n")
    .append(map.get("path")).append("\n")
    .append(map.get("timeStamp") != null ? map.get("timeStamp") : timeStamp).append("\n")
    .append(map.get("nonceStr") != null ? map.get("nonceStr") : nonceStr).append("\n")
    .append(map.get("paramMap") == null ? "" : map.get("paramMap")).append("\n")
    .toString();

    String signAuthorization = null;
    try {
    signAuthorization = WeChatConstant.generateSignature(signAuthorizationStr, map.get("apiclientKey"));
    } catch (Exception e) {
    logger.error("请求头签名异常:{}", e);
    throw new RuntimeException("请求头签名失败!!", e);
    }

    String authorization = new StringBuffer()
    .append("WECHATPAY2-SHA256-RSA2048 ")
    .append("mchid=\"").append(map.get("mchid"))
    .append("\",nonce_str=\"").append(map.get("nonceStr") != null ? map.get("nonceStr") : nonceStr)
    .append("\",signature=\"").append(signAuthorization)
    .append("\",timestamp=\"").append(map.get("timeStamp") != null ? map.get("timeStamp") : timeStamp)
    .append("\",serial_no=\"").append(map.get("serialNO")).append("\"").toString();
    logger.info("签名结果:{}", authorization);
    return authorization;
    }
    }
    WeChatConstant
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    import java.security.InvalidKeyException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.SecureRandom;
    import java.security.Signature;
    import java.security.SignatureException;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.util.Base64;
    import java.util.Random;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public interface WeChatConstant {
    public static final Logger logger = LoggerFactory.getLogger(WeChatConstant.class);

    /**
    * 微信小程序
    */
    public static final String WECHAT_MIN_HTTP = "https://api.weixin.qq.com/sns/jscode2session?appid=";//微信小程序登录认证地址
    public static final String WECHAT_MIN_CODE = "&js_code=";//微信小程序登录认证code
    public static final String WECHAT_MIN_SESSION_KEY = "session_key";//微信小程序登录认证session_key

    /**
    * 微信小程序和微信公众号公用的
    */
    public static final String WECHAT_MIN_AND_WECHAT_WEB_SECRET = "&secret=";//微信小程序和微信公众号登录认证秘钥
    public static final String WECHAT_MIN_AND_WECHAT_WEB_GRANT_TYPE = "&grant_type=authorization_code";//微信小程序和微信公众号登录认证方式申明
    public static final String WECHAT_MIN_AND_WECHAT_WEB_OPENID = "openid";//微信小程序和微信公众号登录openid

    /**
    * 微信公众号
    * 获取code的地址
    * https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxecfc9f&redirect_uri=https%3A%2F%2F3b91-120-202-35-88.ngrok.io%2Fapi%2Foauth%2Fadmin%2FgetWeChatCode&response_type=code&scope=snsapi_userinfo&state=wxecfc9ff#wechat_redirect
    */
    public static final String WECHAT_WEB_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxecfc9ffc1";// 微信公众号登录认证地址
    public static final String WECHAT_WEB_CODE = "&code=";//微信公众号登录认证code

    //https://api.weixin.qq.com/sns/userinfo?access_token=aaaaaaaaaaaaaaa&openid=ovmHY570pDeUcRyF7q3-8zDxiPHw&lang=zh_CN
    public static final String WECHAT_WEB_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=";//微信公众号获取用户openid的地址
    public static final String WECHAT_WEB_OPENID_KEY = "&openid=";//微信公众号获取openid时的Key
    public static final String WECHAT_WEB_LANG = "&lang=zh_CN";//微信公众号获取openid时的语言
    public static final String WECHAT_WEB_SECRET = "1f2ebf415c39";//微信公众号appID对应的秘钥

    public static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    public static final Random RANDOM = new SecureRandom();

    /**
    * 获取随机字符串 Nonce Str
    * @return String 随机字符串
    */
    public static String generateNonceStr() {
    char[] nonceChars = new char[32];
    for (int index = 0; index < nonceChars.length; ++index) {
    nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
    }
    return new String(nonceChars);
    }

    /**
    * 获取当前时间戳,单位秒
    * @return
    */
    public static String getCurrentTimestamp() {
    return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /**
    * 生成签名
    * @param signStr=============签名串
    * @param privateKeyBody======私钥体
    * @return
    */
    public static String generateSignature(String signStr, String privateKeyBody) {
    Signature sign;
    try {
    sign = Signature.getInstance("SHA256withRSA");
    sign.initSign(getPrivateKey(privateKeyBody));
    sign.update(signStr.getBytes());
    return Base64.getEncoder().encodeToString(sign.sign());
    } catch (InvalidKeyException e) {
    throw new RuntimeException("无效的秘钥格式", e);
    } catch (NoSuchAlgorithmException e) {
    throw new RuntimeException("当前java环境不支持RSA", e);
    } catch (SignatureException e) {
    throw new RuntimeException("签名异常!!", e);
    }
    }

    /**
    * 私钥加载
    * @param privateKeyBody==私钥体
    * @return
    */
    public static PrivateKey getPrivateKey(String privateKeyBody) {
    logger.info("私钥体:{}", privateKeyBody);
    try {
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBody)));
    } catch (NoSuchAlgorithmException e) {
    logger.error("当前java环境不支持RSA:{}", e);
    throw new RuntimeException("当前Java环境不支持RSA", e);
    } catch (InvalidKeySpecException e) {
    logger.error("无效的秘钥格式:{}", e);
    throw new RuntimeException("无效的秘钥格式", e);
    }
    }
    }

评论