微信申请小微商户相关

ji准备工作:
1.微信支付商户平台升级API证书,升级后才可成功调用本接口。服务商商户号和秘钥apiv3。
2.获取平台证书序列号及明文证书pem文件信息
public class WxGetcertFicatesUtils {

public final static String URL = “https://api.mch.weixin.qq.com/risk/getcertficates”;

/**

  • https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_11
  • @param config 服务商信息
  • @return
  • @throws Exception
    */
    public static String getcertficates(WXPayConfig config) throws Exception {
    Map<String, String> map = new HashMap<>();
    map.put(“mch_id”, config.getMchID());
    map.put(“nonce_str”, WXPayUtil.generateNonceStr());
    map.put(“sign_type”, “HMAC-SHA256”);
    map.put(“sign”, WXPayUtil.generateSignature(map, config.getKey(), WXPayConstants.SignType.HMACSHA256));
    WXPay wxpay = new WXPay(config);
    String str = wxpay.requestWithoutCert(URL, map, config.getHttpConnectTimeoutMs(),
    config.getHttpReadTimeoutMs());
    Map<String, String> certificates = WXPayUtil.xmlToMap(str);
    String certificates1 = certificates.get(“certificates”);
    String data1 = JSON.parseObject(certificates1).get(“data”).toString();
    //去【】
    data1=data1.replace("[", “”);
    data1=data1.replace("]", “”);
    String encrypt_certificate = JSON.parseObject(data1).get(“encrypt_certificate”).toString();
    String serial_no = JSON.parseObject(data1).get(“serial_no”).toString();
    String nonce = JSON.parseObject(encrypt_certificate).get(“nonce”).toString();
    String associated_data = JSON.parseObject(encrypt_certificate).get(“associated_data”).toString();
    String ciphertext = JSON.parseObject(encrypt_certificate).get(“ciphertext”).toString();
    //*获取证书明文
    String s = decryptCertSN(associated_data,nonce,ciphertext, config.getKey());
    //重要勿泄露
    //System.out.println(“替换apiclient_cert.pem的明文信息为:” + s);
    if (certificates.get(“return_code”).equals(“SUCCESS”)) {
    JSONArray data = JSON.parseObject(certificates.get(“certificates”)).getJSONArray(“data”);
    JSONObject obj = data.getJSONObject(0);
    return obj.getString(“serial_no”);
    }
    return null;
    }

    public static void main(String[] args) {

    try {
    MyWxconfig config = new MyWxconfig();
    System.out.println(WxGetcertFicatesUtils.getcertficates(config));
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }

3.获取上传图片要的media_id
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;

import org.apache.commons.codec.binary.Hex;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import XXX.XXX.XXX.XXX.XXX.MyWxconfig;

import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayUtil;

public class WxUploadImgageUtils {

private final static Logger log = LoggerFactory.getLogger(WxUploadImgageUtils.class);

private final static String URL = “https://api.mch.weixin.qq.com/secapi/mch/uploadmedia”;

public static String uploadImgage(String img_url, WXPayConfig config) throws Exception {
String media_hash = md5HashCode(returnBitMap(img_url));
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(“mch_id”, config.getMchID());
paramMap.put(“media_hash”, media_hash);
paramMap.put(“sign_type”, “HMAC-SHA256”);
String sign = sha256Sign(paramMap, config.getKey());

MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.addTextBody(“mch_id”, config.getMchID(), ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addBinaryBody(“media”, returnBitMap(img_url), ContentType.create(“image/jpg”),
img_url.substring(img_url.lastIndexOf("/") + 1));
multipartEntityBuilder.addTextBody(“media_hash”, media_hash, ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addTextBody(“sign_type”, “HMAC-SHA256”, ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addTextBody(“sign”, sign, ContentType.MULTIPART_FORM_DATA);

KeyStore keyStore = KeyStore.getInstance(“PKCS12”);
keyStore.load(config.getCertStream(), config.getMchID().toCharArray());// 这里写密码…默认是你的MCHID
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, config.getMchID().toCharArray()).build();

@SuppressWarnings(“deprecation”)
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { “TLSv1” }, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
HttpPost httpPost = new HttpPost(URL);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000).setConnectionRequestTimeout(10000)
.setSocketTimeout(10000).build();
httpPost.setConfig(requestConfig);
这里的Content-type要设置为"multipart/form-data",否则返回“参数填写有误,请检查后重试”
httpPost.addHeader(HTTP.CONTENT_TYPE, “multipart/form-data; charset=UTF-8”);
httpPost.addHeader(HTTP.USER_AGENT, “wxpay sdk java v1.0 " + config.getMchID());
httpPost.setEntity(multipartEntityBuilder.build());
CloseableHttpResponse response = httpclient.execute(httpPost);
String result = EntityUtils.toString(response.getEntity(), “UTF-8”);
Map<String, String> map = WXPayUtil.xmlToMap(result);
if (map.get(“result_code”).equals(“SUCCESS”)) {
return map.get(“media_id”);
}
return null;
}

public static String upload(String file_url) {
try {
MyWxconfig config = new MyWxconfig();
String media_hash = md5HashCode(returnBitMap(file_url));
String sign_type = “HMAC-SHA256”;
Map<String, Object> paramMap = new HashMap<>();
paramMap.put(“mch_id”, config.getMchID());
paramMap.put(“media_hash”, media_hash);
paramMap.put(“sign_type”, sign_type);
String sign = sha256Sign(paramMap, config.getKey());

MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.addTextBody(“mch_id”, config.getMchID(), ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addBinaryBody(“media”, returnBitMap(file_url), ContentType.create(“image/jpg”),
file_url.substring(file_url.lastIndexOf(”/") + 1));
multipartEntityBuilder.addTextBody(“media_hash”, media_hash, ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addTextBody(“sign_type”, sign_type, ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addTextBody(“sign”, sign, ContentType.MULTIPART_FORM_DATA);
KeyStore keyStore = KeyStore.getInstance(“PKCS12”);
keyStore.load(config.getCertStream(), config.getMchID().toCharArray());// 这里写密码…默认是你的MCHID
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, config.getMchID().toCharArray())
.build();

@SuppressWarnings(“deprecation”)
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { “TLSv1” },
null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpPost httpPost = new HttpPost(URL);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
.setConnectionRequestTimeout(10000).setSocketTimeout(10000).build();
httpPost.setConfig(requestConfig);
这里的Content-type要设置为"multipart/form-data",否则返回“参数填写有误,请检查后重试”
httpPost.addHeader(HTTP.CONTENT_TYPE, “multipart/form-data; charset=UTF-8”);
httpPost.addHeader(HTTP.USER_AGENT, "wxpay sdk java v1.0 " + config.getMchID());
httpPost.setEntity(multipartEntityBuilder.build());
CloseableHttpResponse response = httpclient.execute(httpPost);
String result = EntityUtils.toString(response.getEntity(), “UTF-8”);
return result;
} catch (Exception e) {
log.error(“官方微信–请求失败!{}”, e);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**

  • 对上次文件进行MD5获取其Hash值
  • @param fis
  • @return
    /
    public static String md5HashCode(InputStream fis) {
    try {
    MessageDigest MD5 = MessageDigest.getInstance(“MD5”);
    byte[] buffer = new byte[8192];
    int length;
    while ((length = fis.read(buffer)) != -1) {
    MD5.update(buffer, 0, length);
    }
    return new String(Hex.encodeHex(MD5.digest()));
    } catch (Exception e) {
    e.printStackTrace();
    return null;
    }
    }

    /
    *
  • 获取HMAC-SHA256签名
  • @param paramMap 签名参数(sign不参与签名)
  • @param key 签名密钥
  • @return HMAC-SHA256签名结果
    /
    public final static String sha256Sign(Map<String, Object> paramMap, String key) {
    try {
    String payParam = getSignTemp(paramMap, key);
    Mac sha256_HMAC = Mac.getInstance(“HmacSHA256”);
    SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(“UTF-8”), “HmacSHA256”);
    sha256_HMAC.init(secret_key);
    byte[] array = sha256_HMAC.doFinal(payParam.getBytes(“UTF-8”));
    StringBuilder sb = new StringBuilder();
    for (byte item : array) {
    sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
    }
    String sign = sb.toString().toUpperCase();
    return sign;
    } catch (Exception e) {
    return null;
    }
    }

    /
    *
  • 获取签名参数字符串
  • @param paramMap 签名参数(sign字段不参与签名)
  • @param payKey 签名密钥
  • @return 待签名字符串
    */
    private final static String getSignTemp(Map<String, Object> paramMap, String payKey) {
    ArrayList keyList = new ArrayList<>(paramMap.keySet());
    Collections.sort(keyList);

    StringBuilder signParam = new StringBuilder();
    for (String key : keyList) {
    if (!“sign”.equals(key) && !StringUtils.isEmpty(paramMap.get(key))) {
    signParam.append(key).append("=").append(paramMap.get(key)).append("&");
    }
    }
    signParam.delete(signParam.length() - 1, signParam.length());
    signParam.append("&key=").append(payKey);
    return signParam.toString();
    }

    public static InputStream returnBitMap(String path) {
    URL url = null;
    InputStream is = null;
    try {
    url = new URL(path);
    } catch (MalformedURLException e) {
    e.printStackTrace();
    }
    try {
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 利用HttpURLConnection对象,我们可以从网络中获取网页数据.
    conn.setDoInput(true);
    conn.connect();
    is = conn.getInputStream(); // 得到网络返回的输入流

    } catch (IOException e) {
    e.printStackTrace();
    }
    return is;
    }
    }

4.敏感数据加密
微信官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_12
import java.io.IOException;
import java.io.InputStream;
import java.security.PublicKey;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.security.cert.X509Certificate;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class RSAEncrypt {

private static final String CIPHER_PROVIDER = “SunJCE”;
private static final String TRANSFORMATION_PKCS1Paddiing = “RSA/ECB/PKCS1Padding”;
private static final String CHAR_ENCODING = “UTF-8”;// 固定值,无须修改
private static final String PUBLIC_KEY_FILENAME = “apiclient_cert.pem”;// 平台证书路径,开发人员需根据具体路径修改

// 数据加密方法
private static byte[] encryptPkcs1padding(PublicKey publicKey, byte[] data) throws Exception {
Cipher ci = Cipher.getInstance(TRANSFORMATION_PKCS1Paddiing, CIPHER_PROVIDER);
ci.init(Cipher.ENCRYPT_MODE, publicKey);
return ci.doFinal(data);
}

// 加密后的秘文,使用base64编码方法
private static String encodeBase64(byte[] bytes) throws Exception {
return Base64.getEncoder().encodeToString(bytes);
}

// 对敏感内容(入参Content)加密,其中PUBLIC_KEY_FILENAME为存放平台证书的路径,平台证书文件存放明文平台证书内容,且为pem格式的平台证书(平台证书的获取方式参照平台证书及序列号获取接口,通过此接口得到的参数certificates包含了加密的平台证书内容ciphertext,然后根据接口文档中平台证书解密指引,最终得到明文平台证书内容)
public static String rsaEncrypt(String Content) throws Exception {
Resource resource = new ClassPathResource(PUBLIC_KEY_FILENAME);
final byte[] PublicKeyBytes = input2byte(resource.getInputStream());
X509Certificate certificate = X509Certificate.getInstance(PublicKeyBytes);
PublicKey publicKey = certificate.getPublicKey();
return encodeBase64(encryptPkcs1padding(publicKey, Content.getBytes(CHAR_ENCODING)));
}

public static final byte[] input2byte(InputStream inStream) {
ByteArrayOutputStream swapStream = null;
try {
swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = inStream.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
byte[] in2b = swapStream.toByteArray();

return in2b;
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
swapStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

// 对“hello world进行加密”
public static void main(String[] args) {
try {
System.out.println("after encrypt: " + rsaEncrypt(“hello world”));
} catch (Exception e) {
e.printStackTrace();
}
}
}

5.sign参数放最后
以上条件满足后,可以直接通过WXPay.requestWithCert(…)发送请求。
可能出现:抛出异常java.security.InvalidKeyException: Illegal key size
Illegal key size or default parameters 是指密钥长度受限制
Java运行时环境读到的是受限的policy文件。
policy文件位于${java_home}/jre/lib/security 目录下。
这种限制是因为美国对软件出口的控制。

解决办法:
去除该限制只需下载 Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files,
覆盖上述目录下的对应jar文件(local_policy.jar, US_export_policy.jar)即可。
下载地址:
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
下载包的readme.txt 有安装说明,即替换
${jdk_home}/jre/lib/security
${jre_home}/lib/security
目录下的 local_policy.jar 和 US_export_policy.jar 文件。

签约注意
1.银行卡持卡人必须和身份证姓名一致
2.身份证有效期限按官方要求写
3.开户银行注意,若为邮储银行写全名邮政储蓄银行
4.商户简称,不要随意只写水果店,饭店,商店,至少写XX水果店,XX饭店/商店
5.售卖商品/提供服务描述写官方规定的描述
6.扫码签约时系统会验证微信实名信息是否为申请单商户本人,若扫码后报错,请先确认商户微信号是否已通过绑卡认证
7.一个微信只能绑定一次,慎用。
8.签约成功后,再申请只要查询状态成功,后台就会多出一个小微商户号,尽管没用但很烦。
9.签约后要进行支付不需要配置绑定,关注和js支付目录。
10.支付成功后金额T+1天会自动提现到银行卡,手续费与申请签约时的费率有关。
11.Java实现AES加密,抛出异常java.security.InvalidKeyException: Illegal key size
支付宝签约官方文档:https://docs.open.alipay.com/20190114195458793939/quickstart/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值