微信境外支付(附PHP例子,JAVA工具类)

官方API:https://wechatpay-api.gitbook.io/wechatpay-api-v3/

推荐文章:https://blog.csdn.net/taoweifeng199311/article/details/100031159

API文档:

链接:https://pan.baidu.com/s/1FrLkL0qj5Y9JuK0VXDpHnQ 
提取码:vc1q 

PHP 例子:

链接:https://pan.baidu.com/s/1lZjsoUjDp6fGOzQqvV2JsQ 
提取码:askc 

遇到问题:

  • java.security.InvalidKeyException: Illegal key size

解决方法:

产生错误原因:为了数据代码在传输过程中的安全,很多时候我们都会将要传输的数据进行加密,然后等对方拿到后再解密使用。我们在使用AES加解密的时候,在遇到128位密钥加解密的时候,没有进行什么特殊处理;然而,在使用256位密钥加解密的时候,如果不进行特殊处理的话,往往会出现这个异常java.security.InvalidKeyException: Illegal key size。

为什么会产生这样的错误?

我们做Java开发,或是Android开发,都会先在电脑上安装JDK(Java Development Kit) 并配置环境变量,JDK也就是 Java 语言的软件开发工具包,JDK中包含有JRE(Java Runtime Environment,即:Java运行环境),JRE中包括Java虚拟机(Java Virtual Machine)、Java核心类库和支持文件,而我们今天要说的主角就在Java的核心类库中。在Java的核心类库中有一个JCE(Java Cryptography Extension),JCE是一组包,它们提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现,所以这个是实现加密解密的重要类库。

在我们安装的JRE目录下有这样一个文件夹:%JAVE_HOME%\jre\lib\security(%JAVE_HOME%是自己电脑的Java路径,一版默认是:C:\Program Files\Java,具体看自己当时安装JDK和JRE时选择的路径是什么),其中包含有两个.jar文件:“local_policy.jar ”和“US_export_policy.jar”,也就是我们平时说的jar包,再通俗一点说就是Java中包含的类库(Sun公司的程序大牛封装的类库,供使用Java开发的程序员使用),这两个jar包就是我们JCE中的核心类库了。JRE中自带的“local_policy.jar ”和“US_export_policy.jar”是支持128位密钥的加密算法,而当我们要使用256位密钥算法的时候,已经超出它的范围,无法支持,所以才会报:“java.security.InvalidKeyException: Illegal key size or default parameters”的异常。那么我们怎么解决呢?

如何解决?

解决方案:去官方下载JCE无限制权限策略文件。

jdk 5: http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html#jce_policy-1.5.0-oth-JPR

jdk6: http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html

JDK7的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK8的下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html 

下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件。

如果安装了JDK,还要将两个jar文件也放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件。

具体下载、解压、替换步骤:

1.下载:根据自己使用的jdk版本进入对应的链接下载(我这里是jdk8)

2.解压:

3.替换:(原来的2个jar包你可以备份下)

4.如果不行就重启下软件,刷新下maven

 
————————————————
原文链接:https://blog.csdn.net/dling8/article/details/84061948

  • $key0参数格式错误$

参数错误会导致次错误,本人遇到的是因为openid错误和商业行业编码(merchant_category_code)错误

商业行业编码:

Merchant Category Codes  Merchant Category  商户类目
5309 Duty-free shops 免税店
5311 Department stores 百货商店
5310 Discount shops 折扣商店
5531 Auto and home supply outlets 汽车商店、家庭用品商店
5611 Men’s and boys’ clothing and accessory shops 男子和男童服装及用品商店
5621 Women’s ready-to-wear shops 妇女成衣商店
5631 Women’s accessory and speciality shops 女性用品商店
5641 Children’s and infants’ wear shops 婴儿、儿童服装店
5651 Family clothing shops 家庭服装商店
5655 Sports and riding apparel shops 运动服饰商店
5661 Shoe shops 鞋店
5681 Furriers and fur shops 皮货店
5691 Men’s and women’s clothing shops 成人成衣店
5699 Miscellaneous apparel and accessory shops 各类服装及饰物店
5712 Furniture, home furnishings and equipment shops and manufacturers, except appliances 家具、家庭摆品、家用设备零售商
5722 Household appliance shops 家用电器商店
5944 Jewellery, watch, clock and silverware shops 珠宝、钟表、银器店
5948 Luggage and leather goods shops 箱包、皮具店
5094 Precious stones and metals, watches and jewellery 宝石和金属、手表和珠宝
5331 Variety stores 各类杂货店、便利店
5411 Groceries and supermarkets 大型仓储式超级市场
5200 Home supply warehouse outlets 大型仓储式家庭用品卖场
5697 Tailors, seamstresses, mending and alterations 裁缝、修补、改衣店
5698 Wig and toupee shops 假发商店
5713 Floor covering services 地板商店
5714 Drapery, window covering and upholstery shops 帏帐、窗帘、室内装潢商店
5715 Alcoholic beverage wholesalers 酒精饮料
5718 Fireplaces, fireplace screens and accessories shops 壁炉、壁炉防护网及配件商店
5719 Miscellaneous home furnishing speciality shops 各种家庭装饰专营店
5732 Electronics shops 电子设备商店
5733 Music shops - musical instruments, pianos and sheet music 音乐商店-乐器、钢琴、乐谱
5734 Computer software outlets 计算机软件商店
5735 Record shops 音像制品商店
5921 Package shops - beer, wine and liquor 瓶装酒零售店
5931 Used merchandise and second-hand shops 旧商品店、二手商品店
5932 Antique shop - sale, repair and restoration 古玩店-出售、维修及还原
5937 Antique reproduction shops 古玩复制店
5940 Bicycle shops - sales and service 自行车商店
5941 Sporting goods shops 体育用品店
5942 Bookshops 书店
5943 Stationery, office and school supply shops 文具用品商店、各类办公用品商店
5945 Hobby, toy and game shops 玩具、游戏店
5946 Camera and photographic supply shops 照相器材商店
5947 Gift, card, novelty and souvenir shops 礼品、卡片、装饰品、纪念品商店
5949 Sewing, needlework, fabric and piece goods shops 纺织品及针织品零售
5950 Glassware and crystal shops 玻璃器皿和水晶饰品店
5970 Artist supply and craft shops 工艺美术商店
5971 Art dealers and galleries 艺术商和画廊
5972 Stamp and coin shops 邮票和纪念币商店
5973 Religious goods and shops 宗教品商店
5977 Cosmetic shops 化妆品商店
5978 Typewriter outlets - sales, service and rentals 打字机商店-销售、服务和出租
5992 Florists 花店
5993 Cigar shops and stands 香烟、雪茄专卖店
5994 Newsagents and news-stands 报亭、报摊
5995 Pet shops, pet food and supplies 宠物商店、宠物食品及用品
5997 Electric razor shops - sales and service 电动剃刀商店-销售和服务
5999 Miscellaneous and speciality retail outlets 其他专门零售店
5044 Office, photographic, photocopy and microfilm equipment 办公、影印及微缩摄影器材
5045 Computers, computer peripheral equipment - not elsewhere classified 计算机、计算机外围设备
5131 Piece goods, notions and other dry goods 布料、缝纫用品和其他纺织品
5192 Books, periodicals and newspapers 书、期刊和报纸
5231 Glass, paint and wallpaper shops 玻璃、油漆涂料、墙纸零售
5251 Hardware shops 五金商店
5261 Lawn and garden supplies outlets, including nurseries 草坪、花园用品商店
5422 Freezer and locker meat provisioners 各类肉类零售商
5441 Candy, nut and confectionery shops 糖果及坚果商店
5451 Dairies 乳制品店、冷饮店
5462 Bakeries 面包房、糕点商店
5499 Miscellaneous food shops - convenience and speciality retail outlets 各类食品店及专门食品零售店
5532 Automotive tyre outlets 汽车轮胎经销商
5533 Automotive parts and accessories outlets 汽车零配件商店
5571 Motorcycle shops and dealers 摩托车商店和经销商
7011 Lodging - hotels, motels and resorts 住宿服务(旅馆、酒店、汽车旅馆、度假村等)
7012 Time-sharing villa or holiday home 分时使用的别墅或度假用房
7032 Sporting and recreational camps 运动和娱乐露营地
7033 Trailer parks and camp-sites 活动房车场及露营场所
5811 Caterers 包办伙食,宴会承包商
5812 Eating places and restaurants 就餐场所和餐馆
5814 Fast food restaurants 快餐店
4011 Railroads 铁路运输
4111 Local and suburban commuter passenger transportation, including ferries 本市和市郊通勤旅客运输(包括轮渡)
4112 Passenger railways 铁路客运
4119 Ambulance services 救护车服务
4121 Taxi-cabs and limousines 出租车服务
4131 Bus lines 公路客运
4214 Motor freight carriers and trucking - local and long distance, moving and storage companies and local delivery 货物搬运和托运—当地和长途,移动和存储公司,以及当地递送服务
4215 Courier services - air and ground and freight forwarders 快递服务(空运、地面运输或海运)
4411 Steamships and cruise lines 轮船及巡游航线服务
4457 Boat rentals and leasing 出租船只
4468 Marinas, marine service and supplies 船舶、海运服务提供商
4511 Airlines and air carriers 航空公司
4784 Tolls and bridge fees 路桥通行费
7210 Laundry, cleaning and garment services 洗衣店
7211 Laundry services - family and commercial 洗熨服务(自助洗衣服务)
7216 Dry cleaners 干洗店
7217 Carpet and upholstery cleaning 室内清洁服务(地毯、沙发、家具表面的清洁服务)
7221 Photographic studios 摄影工作室
7230 Beauty and barber shops 美容理发店
7251 Shoe repair shops, shoe shine parlours and hat cleaning shops 修鞋店、擦鞋店、帽子清洗店
7261 Funeral services and crematoriums 殡葬服务
7273 Dating and escort services 婚姻介绍及陪同服务
7311 Advertising services 广告服务
7333 Commercial photography, art and graphics 商业摄影、工艺、绘图服务
7338 Quick copy, reproduction and blueprinting services 复印及绘图服务
7339 Stenographic and secretarial support services 速记、秘书服务(包括各类办公服务)
7342 Exterminating and disinfecting services 灭虫及消毒服务
7349 Cleaning, maintenance and janitorial services 清洁、保养及门卫服务
7361 Employment agencies and temporary help services 职业中介、临时工
7372 Computer programming, data processing and integrated systems design services 计算机编程、数据处理和系统集成设计服务
7375 Information retrieval services 信息检索服务
7393 Detective agencies, protective agencies and security services, including armoured cars and guard dogs 侦探、保安、安全服务
7394 Equipment, tool, furniture and appliance rentals and leasing 设备、工具、家具和电器出租
7395 Photofinishing laboratories and photo developing 照相洗印服务
7512 Automobile rentals 汽车出租
7513 Truck and utility trailer rentals 卡车及拖车出租
7519 Motor home and recreational vehicle rentals 房车和娱乐车辆出租
7523 Parking lots and garages 停车场
7531 Automotive body repair shops 车体维修店
7534 Tyre retreading and repair shops 轮胎翻新、维修店
7535 Automotive paint shops 汽车喷漆店
7538 Automotive service shops (non-dealer) 汽车服务商店(非经销商)
7542 Car washes 洗车
7549 Towing services 拖车服务
7622 Electronics repair shops 电器设备维修
7623 Air conditioning and refrigeration repair shops 空调、制冷设备维修
7629 Electrical and small appliance repair shops 电器设备、小家电维修
7631 Watch, clock and jewellery repair shops 手表、钟表和首饰维修店
7641 Furniture reupholstery, repair and refinishing 家具维修、翻新
7692 Welding services 焊接维修服务
7699 Miscellaneous repair shops and related services 各类维修店及相关服务
7295 Babysitting and housekeeping services 家政服务
7296 Clothing rentals - costumes, uniforms and formal wear 出租衣物-服装、制服和正式场合服装
4900 Utilities - electric, gas, water and sanitary 公共事业(电力、煤气、自来水、清洁服务)
5541 Service stations (with or without ancillary services) 加油站、服务站
5542 Automated fuel dispensers 自助加油站
4582 Airports, flying fields and airport terminals 机场服务
5511 Car and truck dealers (new and used) sales, services, repairs, parts and leasing 汽车货车经销商-新旧车的销售、服务、维修、零件及出租
5521 Car and truck dealers (used only) sales, service, repairs, parts and leasing 汽车货车经销商-专门从事旧车的销售、服务、维修、零件及出租
9400 Embassy and consulate fees 使领馆收费
9402 Postal Services - Government Only 国家邮政服务
4733 Ticketing 票务
4722 Travel agencies and tour operators 旅行社
7829 Motion picture and video tape production and distribution 电影和录像创作、发行
7832 Motion picture theatres 电影院
7841 Video tape rentals 音像制品出租商店
7911 Dance halls, studios and schools 歌舞厅
7922 Theatrical producers (except motion pictures) and ticket agencies 戏剧制片(不含电影)、演出和票务
7932 Billiard and pool establishments 台球、撞球场所
7933 Bowling alleys 保龄球馆
7941 Commercial sports, professional sports clubs, athletic fields and sports promoters 商业运动
7991 Tourist attractions and exhibits 景点、展览
7992 Public golf courses 公开高尔夫球赛
7993 Video amusement game supplies 电子游戏等
7994 Video game arcades and establishments 大型游戏机和游戏场所
7996 Amusement parks, circuses, carnivals and fortune tellers 游乐园、马戏团、嘉年华、占卜
7997 Membership clubs (sports, recreation, athletic), country clubs and private golf courses 会员俱乐部(体育、娱乐、运动等)、乡村俱乐部以及私人高尔夫课程班
7998 Aquariums, seaquariums and dolphinariums 水族馆、海洋馆和海豚馆
5813 Drinking places (alcoholic beverages) - bars, taverns, night-clubs, cocktail lounges and discothèques 饮酒场所(酒吧、酒馆、夜总会、鸡尾酒大厅、迪斯科舞厅)
7297 Massage parlours 按摩店
7298 Health and beauty spas 保健及美容SPA
4812 Telecommunication equipment and telephone sales 电信设备和销售
4814 Telecommunication services 电信服务,包括本地和长途电话、信用卡电话、磁卡电话和传真
4815 Monthly summary telephone charges 月结电话服务
4816 Computer network information services 计算机网络/信息服务
4899 Cable and other pay television services 有线和其他付费电视服务
7280 private hospital 私人医院
8011 Doctors and physicians - not elsewhere classified 其他医疗卫生活动
8021 Dentists and orthodontists 牙科医生
8031 Osteopaths 正骨医生
8041 Chiropractors 按摩医生
8042 Optometrists and ophthalmologists 眼科医生
8043 Opticians, optical goods and eyeglasses 光学产品、眼镜店
8049 Podiatrists and chiropodists 手足病医生
8050 Nursing and personal care facilities 护理和照料服务
8062 Hospitals 公立医院
8071 Medical and dental laboratories 医学及牙科实验室
8099 Medical services and health practitioners - not elsewhere classified 其他医疗保健服务
5912 Drug stores and pharmacies 药店、药房
5975 Hearing aids - sales, service and supplies 助听器-销售、服务和用品
5976 Orthopaedic goods and prosthetic devices 假肢店(整形外科用品、辅助设备)
5047 Dental laboratory medical ophthalmic hospital equipment and supplies 牙科/实验室/医疗/眼科医院器材和用品
8211 Elementary and secondary schools 中小学校(公立)
8220 Colleges, universities, professional schools and junior colleges 普通高校(公立)
8241 Correspondence schools 函授学校(成人教育)
8244 Business and secretarial schools 商业和文秘学校(中等专业学校)
8249 Trade and vocational schools 贸易和职业学校(职业技能培训)
8299 Schools and educational services - not elsewhere classified 其他学校和教育服务
8351 Child care services 儿童保育服务(含学前教育)

 

  • 工具类

AesUtil.java 微信通知解密用

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

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;


public class AesUtil {

    private       Logger logger          = LoggerFactory.getLogger(AesUtil.class);
    static final  int    KEY_LENGTH_BYTE = 32;
    static final  int    TAG_LENGTH_BIT  = 128;
    private final byte[] aesKey;

    public AesUtil(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) {
            logger.error("境外支付解密", e);
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            logger.error("境外支付解密", e);
            throw new IllegalArgumentException(e);
        }
    }
}

WxPayApi.java 签名、解签用

package com.yogovi.core.service.weixin.v3;

import com.alibaba.fastjson.JSON;
import com.yogovi.core.entity.weixin.v3.NotifyV3;
import com.yogovi.core.service.impl.weixin.v3.AesUtil;
import com.yogovi.core.service.weixin.WXPayUtil;
import com.yogovi.core.entity.weixin.v3.notify.NotifyData;
import okhttp3.HttpUrl;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;


/**
 * 境外微信支付V3
 *
 * @author hangyin
 * @since 2019-09-26
 */
public class WxPayApi {

    private static Logger logger = WXPayUtil.getLogger();

    /**
     * 签名生成
     *
     * @param method       请求类型GET、POST
     * @param url          请求url
     * @param body         GET请求时body传"",POST请求时body为请求参数的json串
     * @param merchantId   商户号
     * @param certSerialNo API证书序列号
     * @param keyPath      API证书路径
     * @param nonceStr     随机字符串
     * @param timeStamp    当前秒数
     * @return
     * @throws Exception
     */
    public static String getToken(String method, String url, String body, String merchantId, String certSerialNo,
                String keyPath, String nonceStr, String timeStamp) throws Exception {
        String signStr;
        HttpUrl httpurl = HttpUrl.parse(url);
        if (StringUtils.isEmpty(body)) {
            body = "";
        }
        String message = buildMessage(method, httpurl, timeStamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"), keyPath);
        signStr = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + merchantId
                    + "\",nonce_str=\"" + nonceStr
                    + "\",timestamp=\"" + timeStamp
                    + "\",serial_no=\"" + certSerialNo
                    + "\",signature=\"" + signature + "\"";
        logger.info("Authorization Token:" + signStr);
        return signStr;
    }

    public static String buildMessage(String method, HttpUrl url, String timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }
        return method + "\n"
                    + canonicalUrl + "\n"
                    + timestamp + "\n"
                    + nonceStr + "\n"
                    + body + "\n";
    }

    public static String sign(byte[] message, String keyPath) throws Exception {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(keyPath));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * 获取私钥。
     *
     * @param filename 私钥文件路径  (required)
     * @return 私钥对象
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException {
        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
        logger.info("File content:" + content);
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                        .replace("-----END PRIVATE KEY-----", "")
                        .replaceAll("\\s+", "");
            logger.info("privateKey:" + privateKey);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(
                        new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            logger.info("异常:" + e);
            throw new RuntimeException("无效的密钥格式");
        }
    }

    /**
     * 调起微信支付签名
     *
     * @param appId
     * @param timestamp
     * @param nonceStr
     * @param packages
     * @param prvKeyPath 私钥证书路径
     * @return
     * @throws Exception
     */
    public static String paySign(String appId, String timestamp, String nonceStr, String packages, String prvKeyPath)
                throws Exception {
        String message = appId + "\n"
                    + timestamp + "\n"
                    + nonceStr + "\n"
                    + packages + "\n";
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(prvKeyPath));
        sign.update(message.getBytes("utf-8"));
        return Base64.getEncoder().encodeToString(sign.sign());
    }

    /**
     * 微信境外支付异步通知参数解密方式
     *
     * @param apiKey   Api密钥
     * @param notifyV3 通知对象
     * @return
     * @throws Exception
     */
    public static NotifyData decrypt(String apiKey, NotifyV3 notifyV3)
                throws Exception {
        AesUtil aesUtil = new AesUtil(apiKey.getBytes(StandardCharsets.UTF_8));
        String data = notifyV3.getResource().getAssociated_data();
        String nonce = notifyV3.getResource().getNonce();
        String ciphertext = notifyV3.getResource().getCiphertext();
        String res = aesUtil.decryptToString(
                    data.getBytes(StandardCharsets.UTF_8),
                    nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        return JSON.parseObject(res, NotifyData.class);
    }
}

 

你可能感兴趣的:(微信,微信支付)