支付宝加密方式:非对称加密(RSA)
支付宝支付过程(如图 1234 流程)
1-商户私钥加签,发送数据和公钥公钥到支付宝 ,
2-支付宝用商户告诉的公钥验签
3-支付宝私钥加签,发送数据和公钥告诉客户支付成功,
4-客户拿支付宝公钥验证。
支付流程(示列 : 电脑网站支付)
3-1支付宝开放平台 (alipay.com) 进入API文档
3-2下载对应语言的用例
3-3支付宝沙箱环境(控制台 沙箱应用中,沙箱环境是支付宝的测试环境)
生成私钥 以及公钥
3-4引入依赖
<!-- 支付宝sdk -->
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.28.ALL</version>
</dependency>
3-5抽取支付宝配置
@ConfigurationProperties(prefix = "alipay") 配置的值写在application.properties中,
如下付宝相关的配置
@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AlipayTemplate {
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public String app_id;
// 商户私钥,您的PKCS8格式RSA2私钥
public String merchant_private_key;
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public String alipay_public_key;
// 服务器[异步通知]页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
// 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
public String notify_url;
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//同步通知,支付成功,一般跳转到成功页
public String return_url;
// 签名方式
private String sign_type;
// 字符编码格式
private String charset;
//订单超时时间
private String timeout = "1m";
// 支付宝网关; https://openapi.alipaydev.com/gateway.do
public String gatewayUrl;
public String pay(PayVo vo) throws AlipayApiException {
//AlipayClient alipayClient = new DefaultAlipayClient(AlipayTemplate.gatewayUrl, AlipayTemplate.app_id, AlipayTemplate.merchant_private_key, "json", AlipayTemplate.charset, AlipayTemplate.alipay_public_key, AlipayTemplate.sign_type);
//1、根据支付宝的配置生成一个支付客户端
AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,
app_id, merchant_private_key, "json",
charset, alipay_public_key, sign_type);
//2、创建一个支付请求 //设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(return_url);
alipayRequest.setNotifyUrl(notify_url);
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = vo.getOut_trade_no();
//付款金额,必填
String total_amount = vo.getTotal_amount();
//订单名称,必填
String subject = vo.getSubject();
//商品描述,可空
String body = vo.getBody();
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"timeout_express\":\""+timeout+"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
String result = alipayClient.pageExecute(alipayRequest).getBody();
//会收到支付宝的响应,响应的是一个页面,只要浏览器显示这个页面,就会自动来到支付宝的收银台页面
System.out.println("支付宝的响应:"+result);
return result;
}
}
#支付宝相关的配置
alipay.app_id=
alipay.merchant_private_key=
alipay.alipay_public_key=
alipay.notify_url=http://hjl.mynatapp.cc/payed/notify
alipay.return_url=http://member.gulimall.com/memberOrder.html
alipay.sign_type=RSA2
alipay.charset=utf-8
alipay.gatewayUrl=https://openapi.alipaydev.com/gateway.do
3-6前置 安装内网穿透工具(我们的地址映射到外网),用于外部访问支付宝支付页(自行安装:花生壳等)
3-7操作流程:页面点击跳转支付宝支付页面,链接如下,以及接口
<a th:href="'http://order.gulimall.com/aliPayOrder?orderSn='+${submitOrderResp.order.orderSn}">支付宝</a>
跳转接口:alipayTemplate.pay(payVo) 调用支付宝接口,返回页面
/**
* 用户下单:支付宝支付
* 1、让支付页让浏览器展示
* 2、支付成功以后,跳转到用户的订单列表页
* @param orderSn
* @return
* @throws AlipayApiException
*/
@ResponseBody
//produces 告诉产生html 页面
@GetMapping(value = "/aliPayOrder",produces = "text/html")
public String aliPayOrder(@RequestParam("orderSn") String orderSn) throws AlipayApiException {
PayVo payVo = orderService.getOrderPay(orderSn);
//返回的是一个页面 直接交给浏览器就行
String pay = alipayTemplate.pay(payVo);
System.out.println(pay);
return pay;
}
3-8 return_url支付成功跳转,同步跳转路径回调页面,一般支付成功展示列表页
3-9 notify_url 支付宝异步回调地址,验签同时修改我们数据状态
异步回调地址规则,具体可以看官方文档
内网穿透工具转到我的电脑,通过host文件访问nginx时,请求头为外网的请求头
所以需要拦击支付请求替换请求头
#支付宝外网穿透拦击支付请求转到订单服务
location /payed/notify {
proxy_pass http://gulimall;
proxy_set_header Host order.gulimall.com;
}
@RestController
public class OrderPayedListener {
@Autowired
private OrderService orderService;
@Autowired
private AlipayTemplate alipayTemplate;
@PostMapping(value = "/payed/notify")
public String handleAlipayed(PayAsyncVo asyncVo, HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
// 只要收到支付宝的异步通知,返回 success 支付宝便不再通知
// 获取支付宝POST过来反馈信息
//TODO 需要验签
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
/**
*调用SDK验证签名
*/
boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayTemplate.getAlipay_public_key(),
alipayTemplate.getCharset(), alipayTemplate.getSign_type());
if (signVerified) {
System.out.println("签名验证成功...");
//去修改订单状态
String result = orderService.handlePayResult(asyncVo);
return result;
} else {
System.out.println("签名验证失败...");
return "error";
}
}
@PostMapping(value = "/pay/notify")
public String asyncNotify(@RequestBody String notifyData) {
//异步通知结果
return orderService.asyncNotify(notifyData);
}
}
本文详细介绍了支付宝基于RSA非对称加密的支付流程,包括商户使用私钥加签,支付宝公钥验签,支付宝私钥加签及客户端验证。同时,展示了如何配置支付宝SDK,设置支付参数,以及处理支付成功的同步和异步回调通知。文中还提到了内网穿透工具在测试环境中的作用和服务器端对支付宝请求的拦截与验签处理。

738

被折叠的 条评论
为什么被折叠?



