微信App支付 Java服务端
- 统一下单
- Controller层
- Service层
- 支付成功后的回调
- 申请退款
- 退款成功回调
- 获取统一下单请求Token
- 处理返回对象
- 支付异步通知验证签名
- 需要再次签名,返给前端用来唤起支付
- 附上工具类
- 特别说明
统一下单
Controller层
/**
* 微信下单
*
* @param reqDto
* @return
*/
@ApiOperation("微信下单")
@PostMapping("/pay")
public Result<WxPayResDto> wxpay(@RequestBody WxPayReqDto reqDto) {
ValidatorUtils.validateEntity(reqDto);
return iWxService.wxToPay(reqDto.getOrderId());
}
controller 仅提供app端访问
Service层
/**
* 微信下单
*
* @param orderId
* @return
*/
@Override
public Result wxToPay(Long orderId) {
//查询订单
FwServiceOrder order = fwServiceOrderMapper.selectFwServiceOrderById(orderId);
if (StringUtils.isNull(order)) {
return Result.error("订单不存在");
}
if (!"0".equals(order.getStatus())) {
return Result.error("订单状态有误");
}
//订单实际价格
BigDecimal amount = null;
if (StringUtils.isNull(order.getCouponsPrice())) {
amount = order.getPrice();
} else {
amount = order.getPrice().subtract(order.getCouponsPrice());
}
if (amount.intValue() < 0) {
return Result.error("非法操作");
}
//建造者模式构建参数
WxPrePayMainDTO wxPrePayMainDTO = WxPrePayMainDTO.builder()
.appid(WxConfigConstant.APP_ID)
.mchid(WxConfigConstant.MCH_ID)
.description(StringUtils.isEmpty(order.getRemak()) ? "服务下单" : order.getRemak())
.out_trade_no(order.getNumber())
.attach(order.getOrderId() + "")
.notify_url(WxConfigConstant.NOTIFY_URL)
.amount(new WxPrePayAmountDTO(amount.multiply(new BigDecimal(100)).intValue(), "CNY"))
.build();
//获取token
String token = this.getToken(JSON.toJSONString(wxPrePayMainDTO), "POST", "/v3/pay/transactions/app");
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
headers.set("Authorization", token);
logger.info("微信统一下单请求参数======" + JSON.toJSONString(wxPrePayMainDTO));
logger.info("微信统一下单请求token======" + token);
HttpEntity<String> request = new HttpEntity<String>(
JSON.toJSONString(wxPrePayMainDTO), headers);
JSONObject response = null;
try {
response = restTemplate.postForObject("https://api.mch.weixin.qq.com/v3/pay/transactions/app",
request, JSONObject.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString());
this.closeOrder(order.getNumber());
return Result.error(response.getString("message"));
}
String prepay_id = response.getString("prepay_id");
if (StringUtils.isEmpty(prepay_id)) {
return Result.error("支付失败");
}
//需要再次签名,返给前端用来唤起支付
logger.info("微信统一下单请求返回参数======" + response);
AwakenPayDTO awakenPayDTO = this.getAwakenPaySign("prepay_id=" + prepay_id);
awakenPayDTO.setOrderCode(order.getNumber());
awakenPayDTO.setPrepayid(prepay_id);
return Result.success(awakenPayDTO);
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WxPrePayMainDTO {
//应用ID
private String appid;
//直连商户号
private String mchid;
//商品描述
private String description;
//商户订单号
private String out_trade_no;
//附加数据
private String attach;
//通知地址
private String notify_url;
//订单金额
private WxPrePayAmountDTO amount;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WxPrePayAmountDTO {
//总金额 单位是分
private Integer total;
//货币类型
private String currency = "CNY";
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "微信支付返回参数", description = "微信支付返回参数")
public class AwakenPayDTO {
@ApiModelProperty(value = "时间戳", name = "timeStamp", example = "20091225091010")
private long timeStamp;
@ApiModelProperty(value = "随机字符串", name = "nonceStr", example = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS")
private String nonceStr;
@ApiModelProperty(value = "订单详情扩展字符串", name = "packageInfo", example = "Sign=WXPay")
private String packageInfo;
@ApiModelProperty(value = "签名类型", name = "signType", example = "RSA")
private String signType;
@ApiModelProperty(value = "签名", name = "paySign", example = "C380BEC2BFD727A4B6845133519F3AD6")
private String paySign;
@ApiModelProperty(value = "订单编号", name = "orderCode", example = "fw1515125221515")
private String orderCode;
@ApiModelProperty(value = "预支付交易会话ID", name = "prepayid", example = "K8264ILTKCH16CQ2502SI8ZNMTM67VS")
private String prepayid;
}
支付成功后的回调
/**
* 微信支付回调
*
* @param request
* @param response
* @throws Exception
*/
@Override
public FwServiceOrder notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
FwServiceOrder order = null;
Map<String, String> map = new HashMap<>(12);
String result = readData(request);
// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
String plainText = verifyNotify(result, WxConfigConstant.KEY);
if (StringUtils.isNotEmpty(plainText)) {
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "支付成功");
//获取返回参数
String orderId = JSON.parseObject(plainText).getString("attach");
//用户支付金额,单位为分 total -总金额 payer_total-用户支付金额
int payer_total = JSON.parseObject(plainText).getJSONObject("amount").getIntValue("total");
order = fwServiceOrderMapper.selectFwServiceOrderById(Long.parseLong(orderId));
if (StringUtils.isNotNull(order)) {
if (!"0".equals(order.getStatus())) {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "订单状态不满足付款条件");
order = null;
} else {
//支付成功 修改订单信息
order.setStatus("1");
order.setPayType("0");
order.setPayTime(DateUtils.getNowDate());
//分转元
order.setActualPrice(new BigDecimal(payer_total).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
if (fwServiceOrderMapper.updateFwServiceOrder(order) <= 0) {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "支付失败,请重试");
order = null;
}
}
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "订单不存在");
order = null;
}
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "签名错误");
}
response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
response.getOutputStream().write(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
return order;
}
申请退款
/**
* 微信申请退款
*
* @param reqDto
* @return
*/
@Override
public Result wxRefunds(WxRefundsReqDto reqDto) {
//参数判断
if (StringUtils.isEmpty(reqDto.getOut_refund_no())) {
return Result.error("退款单号不可为空");
}
if (StringUtils.isEmpty(reqDto.getOut_trade_no())) {
return Result.error("订单号不可为空");
}
if (StringUtils.isNull(reqDto.getTotal())) {
return Result.error("原订单金额不可为空");
}
if (StringUtils.isNull(reqDto.getRefund())) {
return Result.error("退款金额不可为空");
}
//创建微信退款请求参数
WxPreRefundsMainDTO mainDTO = WxPreRefundsMainDTO.builder()
.out_refund_no(reqDto.getOut_refund_no())
.out_trade_no(reqDto.getOut_trade_no())
.amount(new WxPreRefundsAmountDTO(reqDto.getRefund(), reqDto.getTotal(), "CNY"))
.notify_url(WxConfigConstant.REFUND_NOTIFY_URL)
.reason(StringUtils.isEmpty(reqDto.getReason()) ? "默认退款原因" : reqDto.getReason())
.build();
//获取token
String token = this.getToken(JSON.toJSONString(mainDTO), "POST", "/v3/refund/domestic/refunds");
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
headers.set("Authorization", token);
logger.info("微信申请退款请求参数======" + JSON.toJSONString(mainDTO));
logger.info("微信申请退款请求token======" + token);
HttpEntity<String> request = new HttpEntity<String>(
JSON.toJSONString(mainDTO), headers);
JSONObject response = null;
try {
response = restTemplate.postForObject("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds",
request, JSONObject.class);
} catch (HttpClientErrorException e) {
response = JSONObject.parseObject(e.getResponseBodyAsString());
return Result.error(response.getString("message"));
}
if (StringUtils.isNull(response)) {
return Result.error("退款申请失败,请重试");
}
String status = response.getString("status");
if ("SUCCESS".equals(status)) {
return Result.success("退款申请成功");
} else {
return Result.error("退款申请失败,请重试");
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WxPreRefundsMainDTO {
//原支付交易对应的商户订单号
private String out_trade_no;
//商户退款单号
private String out_refund_no;
//退款原因
private String reason;
//退款结果回调url
private String notify_url;
//金额信息
private WxPreRefundsAmountDTO amount;
}
退款成功回调
@Override
public Result<String> refundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, String> map = new HashMap<>(12);
Result resultData = null;
String result = readData(request);
// 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
String plainText = verifyNotify(result, WxConfigConstant.KEY);
if (StringUtils.isNotEmpty(plainText)) {
response.setStatus(200);
map.put("code", "SUCCESS");
map.put("message", "退款成功");
JSONObject jsonObject = JSON.parseObject(plainText);
resultData = new Result(200, "退款成功", jsonObject.getString("out_refund_no"));
} else {
response.setStatus(500);
map.put("code", "ERROR");
map.put("message", "签名错误");
resultData = new Result(500, "退款失败");
}
response.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
response.getOutputStream().write(JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8));
response.flushBuffer();
return resultData;
}
获取统一下单请求Token
/**
* 获取统一下单请求Token
*
* @param body
* @param method
* @param url
* @return
*/
private String getToken(String body, String method, String url) {
//1.加载证书
KeyPair keyPair = wxPayUtil.createPKCS12("wx/apiclient_cert.p12",
"Tenpay Certificate", WxConfigConstant.MCH_ID);
String nonceStr = wxPayUtil.generateNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
//2.获取签名
String sign = wxPayUtil.requestSign(method, url, timestamp, nonceStr,
body, keyPair);
//3.封装token
String token = wxPayUtil.token(WxConfigConstant.MCH_ID, nonceStr, timestamp, WxConfigConstant.CERTNO, sign);
return token;
}
处理返回对象
/**
* 处理返回对象
*
* @param request
* @return
*/
static String readData(HttpServletRequest request) {
BufferedReader br = null;
try {
StringBuilder result = new StringBuilder();
br = request.getReader();
for (String line; (line = br.readLine()) != null; ) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
return result.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
支付异步通知验证签名
/**
* v3 支付异步通知验证签名
*
* @param body 异步通知密文
* @param key api 密钥
* @return 异步通知明文
* @throws Exception 异常信息
*/
private String verifyNotify(String body, String key) throws Exception {
// 获取平台证书序列号
JSONObject resultObject = JSON.parseObject(body);
JSONObject resource = resultObject.getJSONObject("resource");
String cipherText = resource.getString("ciphertext");
String nonceStr = resource.getString("nonce");
String associatedData = resource.getString("associated_data");
// 你的Apiv3秘钥转换成Utf8的Byte
byte[] aesKey = key.trim().toLowerCase().getBytes("UTF-8");
// 以下微信传来的附加值(很重要)
byte[] associatedDataBytes = associatedData.getBytes("UTF-8");
byte[] nonceBytes = nonceStr.getBytes("UTF-8");
byte[] cipherTextBytes = Base64.decodeBase64(cipherText);
AesUtil aesUtil = new AesUtil(aesKey);
// 密文解密
return aesUtil.decryptToString(
associatedDataBytes,
nonceBytes,
cipherTextBytes
);
}
需要再次签名,返给前端用来唤起支付
/**
* 需要再次签名,返给前端用来唤起支付
*
* @param body
* @return
*/
private AwakenPayDTO getAwakenPaySign(String body) {
//1.加载证书
KeyPair keyPair = wxPayUtil.createPKCS12("wx/apiclient_cert.p12",
"Tenpay Certificate", WxConfigConstant.MCH_ID);
AwakenPayDTO awakenPayDTO = new AwakenPayDTO();
String nonceStr = wxPayUtil.generateNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
//2.获取签名
String sign = wxPayUtil.awakenPaySign(WxConfigConstant.APP_ID, timestamp, nonceStr, body, keyPair);
//3.封装token
awakenPayDTO.setNonceStr(nonceStr);
awakenPayDTO.setPackageInfo(body);
awakenPayDTO.setSignType("RSA");
awakenPayDTO.setTimeStamp(timestamp);
awakenPayDTO.setPaySign(sign);
return awakenPayDTO;
}
附上工具类
/**
* @ProjectName: aila
* @Package: com.aila.api.pay.wx.tool
* @ClassName: AesUtil
* @Author: dujiayu
* @Description: aes工具
* @Date: 2021/7/21 9:47
* @Version: 1.0
*/
public class AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
/**
* @param key APIv3 密钥
*/
public AesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
/**
* 证书和回调报文解密
*
* @param associatedData associated_data
* @param nonce nonce
* @param cipherText ciphertext
* @return {String} 平台证书明文
* @throws GeneralSecurityException 异常
*/
public String decryptToString(byte[] associatedData, byte[] nonce, byte[] cipherText) throws GeneralSecurityException {
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(cipherText), StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
@Component
public class WxPayUtil {
private KeyStore store;
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();
private final Object lock = new Object();
/**
* 获取公私钥.
*
* @param keyPath the key path
* @param keyAlias the key alias
* @param keyPass password
* @return the key pair
*/
public KeyPair createPKCS12(String keyPath, String keyAlias, String keyPass) {
Resource resource = new ClassPathResource(keyPath);//用来读取resources下的文件
// ClassPathResource resource = new ClassPathResource(keyPath);
char[] pem = keyPass.toCharArray();
try {
synchronized (lock) {
if (store == null) {
synchronized (lock) {
store = KeyStore.getInstance("PKCS12");
store.load(resource.getInputStream(), pem);
}
}
}
X509Certificate certificate = (X509Certificate) store.getCertificate(keyAlias);
certificate.checkValidity();
// 证书的序列号
// String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
// 证书的 公钥
PublicKey publicKey = certificate.getPublicKey();
// 证书的私钥
PrivateKey storeKey = (PrivateKey) store.getKey(keyAlias, pem);
return new KeyPair(publicKey, storeKey);
} catch (Exception e) {
throw new IllegalStateException("Cannot load keys from store: " + resource, e);
}
}
/**
* V3 SHA256withRSA 签名.
*
* @param method 请求方法 GET POST PUT DELETE 等
* @param canonicalUrl 例如 https://api.mch.weixin.qq.com/v3/pay/transactions/app?version=1 ——> /v3/pay/transactions/app?version=1
* @param timestamp 当前时间戳 因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持一致
* @param nonceStr 随机字符串 要和TOKEN中的保持一致
* @param body 请求体 GET 为 "" POST 为JSON
* @param keyPair 商户API 证书解析的密钥对 实际使用的是其中的私钥
* @return the string
*/
@SneakyThrows
public String requestSign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair) {
String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body)
.collect(Collectors.joining("\n", "", "\n"));
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(keyPair.getPrivate());
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(sign.sign());
}
@SneakyThrows
public String awakenPaySign(String appid, long timestamp, String nonceStr, String body, KeyPair keyPair) {
String signatureStr = Stream.of(appid, String.valueOf(timestamp), nonceStr, body)
.collect(Collectors.joining("\n", "", "\n"));
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(keyPair.getPrivate());
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
return Base64Utils.encodeToString(sign.sign());
}
/**
* 生成Token.
*
* @param mchId 商户号
* @param nonceStr 随机字符串
* @param timestamp 时间戳
* @param serialNo 证书序列号
* @param signature 签名
* @return the string
*/
public String token(String mchId, String nonceStr, long timestamp, String serialNo, String signature) {
final String TOKEN_PATTERN = "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\","
+ "timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\"";
// 生成token
return String.format(TOKEN_PATTERN,
mchId,
nonceStr, timestamp, serialNo, signature);
}
public 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);
}
/**
* 解密响应体.
*
* @param apiV3Key API V3 KEY API v3密钥 商户平台设置的32位字符串
* @param associatedData response.body.data[i].encrypt_certificate.associated_data
* @param nonce response.body.data[i].encrypt_certificate.nonce
* @param ciphertext response.body.data[i].encrypt_certificate.ciphertext
* @return the string
* @throws GeneralSecurityException the general security exception
*/
public String decryptResponseBody(String apiV3Key, String associatedData, String nonce, String ciphertext) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
byte[] bytes;
try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 请求xml组装
*
* @param parameters
* @return
*/
public static String getRequestXml(SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
sb.append("<" + key + ">" + "<![CDATA[" + value + "]]></" + key + ">");
} else {
sb.append("<" + key + ">" + value + "</" + key + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
public static void main(String[] args) {
WxPayUtil KeyPairFactory = new WxPayUtil();
KeyPair createPKCS12 = KeyPairFactory.createPKCS12("/apiclient_cert.p12", "Tenpay Certificate", "商户号");
String nonceStr = KeyPairFactory.generateNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
String sign = KeyPairFactory.requestSign("GET", "/v3/certificates",
timestamp, nonceStr,
""
, createPKCS12);
String token = KeyPairFactory.token("商户号", nonceStr, timestamp,
"证书号", sign);
System.out.println(token);
}
}
public class WxConfigConstant {
/**
* APP_ID
*/
public static final String APP_ID = "wxf30c210487f84321d";
/**
* APP_SECRET
*/
public static final String APP_SECRET = "bee1813225a6c0caef88ab21b222226c9";
//===================================以下为微信支付部分================================================
/**
* 直连商户号,由微信支付生成并下发
*/
public static final String MCH_ID = "15262958571";
/**
* 密钥key
*/
public static final String KEY = "51a57db9e0a4f1dd2a5113dc05424066b";
/**
* 证书序列号
*/
public static String CERTNO = "4EC503193104E12B14A8E25D1FCDB224C0934DFBC0";
/**
* 微信支付回调通知地址
*/
public static final String NOTIFY_URL = "/api/wxPay/wxPayNotify";
/**
* 退款回调
*/
public static String REFUND_NOTIFY_URL = "/api/wxPay/refundNotify";
}
特别说明
秘钥文件放在了资源目录下,可跟据需要放在任意位置
@Autowired
private RestTemplate restTemplate;
此处注解需在项目中配置注入
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//ms
factory.setConnectTimeout(15000);//ms
return factory;
}
}
微信支付v3大坑
java.security.InvalidKeyException: Illegal key size错误
产生错误原因:为了数据代码在传输过程中的安全,很多时候我们都会将要传输的数据进行加密,然后等对方拿到后再解密使用。我们在使用AES加解密的时候,在遇到128位密钥加解密的时候,没有进行什么特殊处理;然而,在使用256位密钥加解密的时候,如果不进行特殊处理的话,可能会因为jdk版本的问题出现这个异常java.security.InvalidKeyException: Illegal key size。
第一种情况:如果有policy 文件夹,说明此版本为JVM启用 无限制强度管辖策略 有了一种新的更简单的方法。
请在 当前文件夹中查找文件 java.security。
现在用文本编辑器打开java.security,并找到定义java安全性属性crypto.policy的行,它可以有两个值limited或unlimited - 默认值是limited。
默认情况下,您应该能找到一条注释掉的行:
#crypto.policy=unlimited
您可以通过取消注释该行来启用无限制,删除#:
crypto.policy=unlimited
现在重新启动指向JVM的Java应用程序即可。
第二种情况:没有policy 文件夹,而是直接就有local_policy.jar,US_export_policy.jar两个jar包。
去官方下载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
将两个jar文件放到%JAVE_HOME%\jre\lib\security目录下覆盖原来文件。
代码仅供对于v3版的微信支付一知半解的小伙伴提供参考