赞
踩
.privateKey(wxPayConfig.getPrivateKey())
.merchantSerialNumber(wxPayConfig.getMchSerialNo())
.apiV3Key(wxPayConfig.getApiV3Key())
.build();
使用 new RSAAutoCertificateConfig.Builder() 拿到其内部静态类Builder,Builder类继承了抽象类 AbstractRSAConfigBuilder,并调用父类的方法来初始化商户信息放到AbstractRSAConfigBuilder配置类中。调用其内部的build方法构造RSAAutoCertificateProvider.Builder类,同时将商户信息存储到RSAAutoCertificateProvider中,并调用build()方法来下载证书,下载证书的具体步骤:
1、首先租组装商户的签名信息(包括商户证书的序列号、商户私钥、商户号)如下代码段:
credential =
new WechatPay2Credential(
requireNonNull(merchantId),
new RSASigner(requireNonNull(merchantSerialNumber), privateKey));
}
2、构造httpClient,并将商户证书、签名签证器设置到httpclient中。
3、请求微信平台的证书下载地址,进行证书下载,构造证书下载器:
CertificateDownloader downloader =
new CertificateDownloader.Builder()
.certificateHandler(rsaCertificateHandler)
.downloadUrl(REQUEST_URL)
.aeadCipher(aeadCipher)
.httpClient(httpClient)
.build();
其中 `REQUEST_URL = "https://api.mch.weixin.qq.com/v3/certificates?algorithm_type=RSA"` , `aeadCipher` 为APIv3密钥。`构造的httpClient`
4、证书下载:
/**
* 注册证书下载任务 如果是第一次注册,会先下载证书。如果能成功下载,再保存下载器,供定时更新证书使用。如果下载失败,会抛出异常。
* 如果已经注册过,当前传入的下载器将覆盖之前的下载器。如果当前下载器不能下载证书,定时更新证书会失败。
*
* @param merchantId 商户号
* @param type 调用方自定义的证书类型,例如 RSA/ShangMi
* @param downloader 证书下载器
*/
public static void register(String merchantId, String type, CertificateDownloader downloader) {
String key = calculateDownloadWorkerMapKey(merchantId, type);
Runnable worker =
() -> {
Map<String, X509Certificate> result = downloader.download();
certificateMap.put(key, result);
};
// 下载证书,以验证配置是正确的
// 如果错误将抛出异常,fast-fail
worker.run();
// 更新配置
downloadWorkerMap.put(key, worker);
start(defaultUpdateInterval);
}
打开download方法:
/** 下载证书 */
public Map<String, X509Certificate> download() {
HttpRequest httpRequest =
new HttpRequest.Builder()
.httpMethod(HttpMethod.GET)
.url(downloadUrl)
.addHeader(Constant.ACCEPT, " */*")
.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue())
.build();
HttpResponse httpResponse =
httpClient.execute(httpRequest, DownloadCertificateResponse.class);
Map<String, X509Certificate> downloaded = decryptCertificate(httpResponse);
validateCertificate(downloaded);
return downloaded;
}
这里大家注意,重点来了,在下载证书时,sdk将签名封装到了httpClient中,在 `HttpResponse<DownloadCertificateResponse> httpResponse = httpClient.execute(httpRequest, DownloadCertificateResponse.class);` 这段代码中的execute方法中通过构造token值,并将token放到请求的header中,重点看这个方法`getAuthorization(httpRequest)` 这个方法中,使用了商户的私钥将请求body进行签名,并将明文、商户的公钥、签名信息组成token串发送给了微信平台,具体构造token的代码块为:
String token =
“mchid=”"
+ getMerchantId()
+ “”,"
+ “nonce_str=”"
+ nonceStr
+ “”,"
+ “timestamp=”"
+ timestamp
+ “”,"
+ “serial_no=”"
+ signature.getCertificateSerialNumber()
+ “”,"
+ “signature=”"
+ signature.getSign()
+ “”";
请求完成后,微信平台侧会实时将响应数据返回。在商户侧调用`decryptCertificate(httpResponse)` 将响应的数据进行解密,解密时使用我们之前设置的APIv3密钥。紧接着会验证下载证书的有效性会调用 `validateCertificate(downloaded);`具体的验证代码段如下:
PKIXParameters params = new PKIXParameters(trustAnchor);
params.setRevocationEnabled(false);
List<X509Certificate> certs = new ArrayList<>();
certs.add(certificate);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertPath certPath = cf.generateCertPath(certs);
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
validator.validate(certPath, params);
上述代码块用于检查证书是否由可信的根证书颁发,以及证书是否有效。X509Certificate是一种常用的数字证书标准。首先创建一个 PKIXParameters 类型的对象,它是一个用于验证证书路径的参数集合,它的构造器需要一个 trustAnchor 参数,表示可信的根证书,它是一个 Set 类型的对象,它包含了一个或多个根证书的信息。 getInstance(“PKIX”) 返回一个支持 PKIX(公钥基础设施)算法的验证器实例。
证书下载完成会存放到 AutoCertificateService类certificateMap中 ,certificateMap 是一个ConcurrentHashMap ,是线程安全的,可以支持多线程的并发访问和修改,而AutoCertificateService类是一个定时更新证书的服务,它是一个由静态函数构成的工具类。
private static final ConcurrentHashMap<String, Map<String, X509Certificate>> certificateMap =
new ConcurrentHashMap<>();
Map<String, X509Certificate> result = downloader.download();
certificateMap.put(key, result);
**到此微信平台证书的自动下载过程就描述清楚了,下面我们来总结一下具体流程:** (1)商户侧包装商户信息:商户号、商户公钥、商户私钥等信息,并将请求的数据进行签名。将签名和公钥、时间戳、随机数等信息打包成token放到请求头部发送至微信平台侧。 (2)微信测收到请求后获取到认证token,并解析出商户公钥和明文信息,对数据进行验签。同时使用APIv3密钥将证书进行加密同步返回给商户侧。 (3)商户侧收到微信侧的响应数据后,从响应数据解密出证书,应答报文解密后,生成X.509证书对象,也就是将证书从String转为X509Certificate。 (4)验证证书的有效性 (5)将证书存储到AutoCertificateService中的certificateMap 中。 ### APIv3密钥设置 在商户平台中【微信支付商户平台 - 账户中心 - 账户设置 - API安全 - APIv3密钥设置】,这个可使用在线生成器生成地址:<https://www.bchrt.com/tools/suijimima/> ### 商户平台证书和私钥的获取 以下内容来自微信官网:<https://kf.qq.com/faq/161222NneAJf161222U7fARv.html> 1、登录【微信支付商户平台 - 账户中心 - 账户设置 - API安全 - 申请API证书】申请证书,确定后请勿关闭页面 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/cbaca4d8c8d4484f8c5b7d5c8d16efeb.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6a95dfab21a74656ae97b87191350bcd.png) 2、点击下载证书工具;下载后,双击“WXCertUtil.exe”文件,选择安装路径后,点击申请证书 也可通过以下链接下载证书工具: [windows版本]( ) [mac版本]( ) 3、在【证书工具】,填写商户号信息(商户号、商户名称),点击下一步 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b09a7289e9e94f8d9cf0ca5f8dc4f539.png) 4、在【证书工具】,复制证书请求串 (若提示"请粘贴请求串到商户平台获取证书串",请在第5点步骤检查是否已粘贴。可同时尝试手动鼠标复制粘贴的方法) ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b409a322a77c4a82aa43ff5ee92b8778.png) 5、在【商户平台】,粘贴证书请求串 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5de170cb9112467f902a62a73db1bed6.png) 6、在【商户平台】,输入操作密码,安全验证后生成证书串 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fee6d72cd64d4db98605725c84fac0f4.png) 7、在【商户平台】,复制证书串 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/cf5fdb9f8925455ba8dab48ac2239327.png) 8、在【证书工具】,粘贴证书串,点击下一步,申请证书成功 (若提示"证书与本地公私钥不匹配",可能是浏览器禁用了剪切板复制功能。请在操作步骤第7点,操作时使用鼠标选中全部证书串内容(注意右边有下拉框),单击鼠标右键选择复制) ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0d59a1586680427e8517d9471164ba4c.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ca2c1ee7c0284b339f1dfe959b70aa69.png) 提醒:请将生成的证书文件转交给技术人员,由技术人员将证书部署到服务器上(请务必妥善保管证书及私钥,因为私钥文件只能通过证书工具导出,若私钥丢失,则无法找回,只能作废后重新申请。) 9、证书申请成功后,在证书文件夹中解压文件会发现有3个文件:.p12 这个不用管,其中两个文件apiclient\_cert.pem(商户公钥文件)、apiclient\_key(商户私钥文件)。 到此,商户API证书已经获取完毕。 ### 初始化微信配置 为了统一配置微信支付用到的信息,我们在项目的resource目录下创建一个配置文件`wxpay.properties`
wxpay.mch-id=xxxxxxx
wxpay.mch-serial-no=xxxxxxxxxxxxxxxxxxx
wxpay.private-key-path=apiclient_key.pem
wxpay.api-v3-key=xxxxxxxxxxxxxx
wxpay.appid=xxxxxxxxxxx
wxpay.appSecret=xxxxxxxxxxxxxxxxxxxxxxxxx
wxpay.domain=https://api.mch.weixin.qq.com
#微信支付回调地址域名(需要https 并且为备案的域名)
wxpay.notify-domain=https://test.notify.com
#商户私钥
wxpay.private-key=-----BEGIN PRIVATE KEY-----xxxx-----END PRIVATE KEY-----
其对应的配置类如下:
@Configuration
@PropertySource(“classpath:wxpay.properties”) //读取配置文件
@ConfigurationProperties(prefix=“wxpay”) //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
public class WxPayConfig {
// 商户号 private String mchId; // 商户API证书序列号 private String mchSerialNo; // 商户私钥文件 private String privateKeyPath; // APIv3密钥 private String apiV3Key; // APPID private String appid; //小程序密钥 private String appSecret; // 微信服务器地址 private String domain; // 接收结果通知地址 private String notifyDomain; // APIv2密钥 private String partnerKey; //商户私钥字符串 private String privateKey;
}
### 小程序统一下单
本节,主要来以分析小程序统一下单的案例,来说明sdk的使用方式,以及商户证书和平台证书的在调用下单接口时是如何使用的,本节不会过多在当前项目中展开业务代码,只讲解下单接口如何调用,安全验证的过程。
在调用小程序下单接口之前,首先要创建订单数据,调用下单接口时将订单数据传过去,比如订单金额、商品id、订单编号等。微信收到订单后会返回预付订单id以及微信平台返回的微信订单信息,下面来看看具体的调用代码,下面是小程序下单的代码块。
if (config == null){
config = WxInitUtils.getInstance(wxPayConfig);
}
JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
// 填充预下单参数
PrepayRequest request = new PrepayRequest();
//appid
request.setAppid(wxPayConfig.getAppid());
//商户id
request.setMchid(wxPayConfig.getMchId());
//产品描述
assert orderInfo != null;
request.setDescription(orderInfo.getOrderTitle());
//商户订单号
request.setOutTradeNo(orderInfo.getOrderNo());
//通知url
request.setNotifyUrl(wxPayConfig.getNotifyDomain().concat(WxNotifyType.NATIVE_NOTIFY.getType()));
//金额信息 Amount amount = new Amount(); amount.setTotal(orderInfo.getTotalFee()); amount.setCurrency("CNY"); request.setAmount(amount); //用户信息 Payer payer = new Payer(); payer.setOpenid(openId.toString()); request.setPayer(payer); log.info("请求参数 ===> {}" + request.toString()); PrepayWithRequestPaymentResponse response = null; try { // response包含了调起支付所需的所有参数,可直接用于前端调起支付 response = service.prepayWithRequestPayment(request); } catch (Exception e) { log.error("请求下单失败,错误信息" + e.getMessage()); throw new RuntimeException("请求下单失败,错误信息" + e.getMessage()); } //处理返回值 assert response != null; String packageVal = response.getPackageVal(); String prepayId = packageVal;
上述代码中,首先拿到配置信息config,然后调用`JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();` 这个是sdk提供的api,接下来组装好参数之间向微信发起请求,请求的代码段`response = service.prepayWithRequestPayment(request);` 在prepayWithRequestPayment方法中调用了String prepayId = this.jsapiService.prepay(request).getPrepayId(); 在prepay方法中才是真正的发起请求,重点来看下请求的代码段:
HttpRequest httpRequest = (new HttpRequest.Builder()).httpMethod(HttpMethod.POST).url(requestPath).headers(headers).body(this.createRequestBody(request)).build();
HttpResponse httpResponse = this.httpClient.execute(httpRequest, PrepayResponse.class);
在execute方法中又调用了如下代码,和下载证书的接口调用是一样的。
HttpRequest innerRequest =
new Builder()
.url(httpRequest.getUrl())
.httpMethod(httpRequest.getHttpMethod())
.headers(httpRequest.getHeaders())
.addHeader(AUTHORIZATION, getAuthorization(httpRequest))
.addHeader(USER_AGENT, getUserAgent())
.body(httpRequest.getBody())
.build();
OriginalResponse originalResponse = innerExecute(innerRequest);
validateResponse(originalResponse);
重点来关注Authorization, 的组成如下:
>
> Authorization: 认证类型 签名信息
>
>
>
具体组成为:
**认证类型:** 目前为WECHATPAY2-SHA256-RSA2048
**签名信息**
发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid
商户API证书序列号serial\_no,用于声明所使用的证书
请求随机串nonce\_str
时间戳timestamp
签名值signature
示例如下:
>
> ‘Authorization: WECHATPAY2-SHA256-RSA2048 mchid=“1900009191”,nonce\_str=“593BEC0C930BF1AFEB40B4A08C8FB242”,signature=“uOVRnA4qG/MNnYzdQxJanN+zU+lTgIcnU9BxGw5dKjK+VdEUz2FeIoC+D5sB/LN+nGzX3hfZg6r5wT1pl2ZobmIc6p0ldN7J6yDgUzbX8Uk3sD4a4eZVPTBvqNDoUqcYMlZ9uuDdCvNv4TM3c1WzsXUrExwVkI1XO5jCNbgDJ25nkT/c1gIFvqoogl7MdSFGc4W4xZsqCItnqbypR3RuGIlR9h9vlRsy7zJR9PBI83X8alLDIfR1ukt1P7tMnmogZ0cuDY8cZsd8ZlCgLadmvej58SLsIkVxFJ8XyUgx9FmutKSYTmYtWBZ0+tNvfGmbXU7cob8H/4nLBiCwIUFluw==”,timestamp=“1554208460”,serial\_no=“1DDE55AD98ED71D6EDD4A4A16996DE7B47773A8C”’
>
>
>
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/a48445e432b5c80cd48d22263d166d90.png)
![img](https://img-blog.csdnimg.cn/img_convert/de9ae810f42ff8c2e9b2205a03928141.png)
![img](https://img-blog.csdnimg.cn/img_convert/4d47a4a6cb973a815f2573b67e66d477.png)
![img](https://img-blog.csdnimg.cn/img_convert/b9fae638eb75520e34fc5a40be7ce194.png)
![img](https://img-blog.csdnimg.cn/img_convert/1d1859ea01a661b1a78ca2d55221ae90.png)
![img](https://img-blog.csdnimg.cn/img_convert/6a435b8595caccf5d3b818af0a781e59.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!**
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)**
![img](https://img-blog.csdnimg.cn/img_convert/33906773d572b4438acc784c02980dca.png)
还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!
王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。
对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!
【完整版领取方式在文末!!】
***93道网络安全面试题***
![](https://img-blog.csdnimg.cn/img_convert/6679c89ccd849f9504c48bb02882ef8d.png)
![](https://img-blog.csdnimg.cn/img_convert/07ce1a919614bde78921fb2f8ddf0c2f.png)
![](https://img-blog.csdnimg.cn/img_convert/44238619c3ba2d672b5b8dc4a529b01d.png)
内容实在太多,不一一截图了
### 黑客学习资源推荐
最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/598837
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。