持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情
每日英语:
No need to hurry. No need to sparkle. No need to be anybody but oneself.
翻译:不必行色匆匆,不必闪耀夺目,不必成为别人,只需做好自己。 ——弗吉尼亚·伍尔芙
支付安全验签流程
支付过程如上图,用户发起预支付下单,会将订单信息转成支付信息,并将支付信息传给支付服务,支付服务再调用微信服务器实现预下单操作。
如果当前用户是一个程序员,能读懂一些代码,此时会存在很多隐患问题,如果用户把支付金额修改了,就会给公司造成很大的损失,此时我们需要对数据进行安全处理。
验签:
需要传给支付服务器的数据,我们使用订单服务加密处理再返回到客户端,客户端将加密数据传给支付服务器,支付服务器对数据进行安全校验,校验通过了再下单,这个过程就是金融行业常用的验签操作。整个操作流程如下:
验签实现
将AESUtil.java、MD5.java、Signature.java导入到mall-common工程的com.xz.mall.util包下。
同时记得导入FastJSON依赖包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
1)初始化Signature
在mall-order-service工程的bootstrap.yml中添加秘钥配置和加盐配置,代码如下:
#支付配置
payconfig:
#支付安全校验
aes:
#AES加密秘钥
skey: ab2cc473d3334c39
#验签盐
salt: XPYQZb1kMES8HNaJWW8+TDu/4JdBK4owsU9eXCXZDOI=
在mall-order-service工程中创建com.xz.mall.order.config.SecurityConfig用于初始化Signature,代码如下:
@Configuration
public class SecurityConfig {
//秘钥
@Value("${payconfig.aes.skey}")
private String skey;
//验签加盐值
@Value("${payconfig.aes.salt}")
private String salt;
/***
* 验签对象
*/
@Bean(value = "signature")
public Signature signature(){
return new Signature(skey,salt);
}
}
2)支付参数处理
在mall-order-service工程中创建com.xz.mall.order.pay.WeixinPayParam,将订单信息封装到统一下单的参数中,并使用Signature进行签名和加密,代码如下:
@Component
public class WeixinPayParam {
@Autowired
private Signature signature;
/****
* 微信支付参数封装
* 对参数进行签名
* 对整体参数进行加密
* @return
*/
public String weixinParam(Order order, HttpServletRequest request) throws Exception {
//定义Map封装参数
Map<String,String> dataMap = new HashMap<String,String>();
dataMap.put("body", "商城订单-"+order.getId());
dataMap.put("out_trade_no", order.getId());
dataMap.put("device_info", "PC");
dataMap.put("fee_type", "CNY");
//dataMap.put("total_fee", String.valueOf(order.getMoneys()));
dataMap.put("total_fee", "1"); //1分钱测试
dataMap.put("spbill_create_ip", IPUtils.getIpAddr(request));
dataMap.put("notify_url", "http://www.example.com/wxpay/notify");
dataMap.put("trade_type", "NATIVE"); // 此处指定为扫码支付
//生成签名,并且参数加密
return signature.security(dataMap);
}
}
修改mall-order-service在该工程中com.xz.mall.order.controller.OrderController里添加方法里增加支付数据处理,代码如下:
@Autowired
private WeixinPayParam weixinPayParam;
/***
* 添加订单
*/
@PostMapping
public RespResult add(@RequestBody Order order,HttpServletRequest request) throws Exception {
String userName = "gp";
order.setUsername(userName);
order.setCreateTime(new Date());
order.setUpdateTime(order.getCreateTime());
order.setId(IdWorker.getIdStr());
order.setOrderStatus(0);
order.setPayStatus(0);
order.setIsDelete(0);
//添加订单
Boolean bo = orderService.add(order);
//支付信息封装
if(bo){
//加密字符
String ciptext = weixinPayParam.weixinParam(order,request);
return RespResult.ok(ciptext);
}
return RespResult.error(RespCode.SYSTEM_ERROR);
}
3)数据验证
在mall-pay-service工程中初始化Signature,将工程mall-order-service中的com.xz.mall.order.config.SecurityConfig拷贝到mall-pay-service工程的com.xz.mall.pay.config包下。
修改mall-pay-service工程中的com.xz.mall.pay.controller.WeixinPayController#pay方法,代码如下:
@Autowired
private Signature signature;
/*****
* 预下单
* ciptext:支付信息加密字符串 AES加密,包含验签
* @return
* @throws Exception
*/
@GetMapping(value = "/pay")
public RespResult<Map> pay(@RequestParam(value = "ciptext")String ciphertext) throws Exception {
//数据解析,并验签校验
Map<String, String> map = signature.security(ciphertext);
//1分钱测试
if(map!=null){
Map<String, String> resultMap = weixinPayService.preOrder(map);
resultMap.put("orderNumber",map.get("out_trade_no"));
resultMap.put("money",map.get("total_fee"));
return RespResult.ok(resultMap);
}
return RespResult.error("支付系统繁忙,请稍后再试!");
}
总结
本篇主要讲述了一下支付安全验签流程,还有具体的验签代码实现。