签名验证
<p>[TOC]</p>
<h2>签名验证</h2>
<p>平台回调商家时,会用密钥对请求数据签名,签名方式同商家请求平台时签名规则相同,具体请看<em>签名生成</em>。</p>
<p>商户可以按照下述步骤验证应答或者回调的签名。</p>
<h3>构造验签名串</h3>
<ol>
<li>
<p>从请求头中获取鉴权信息</p>
<ul>
<li>businessId</li>
<li>nonce</li>
<li>signType (为空时不参加签名计算)</li>
<li>timestamp</li>
</ul>
</li>
<li>
<p>以字符串形式接收请求体(如果使用对象的方式接收,验签时可能会导致字段顺序不一致导致验签失败):</p>
<pre><code class="language-java">@RequestBody String param</code></pre>
</li>
<li>按<em>签名生成</em>中的构造签名串方式拼接待签名字符串</li>
</ol>
<h3>获取应答签名</h3>
<p>应答签名通过HTTP头<code>sign</code>传递</p>
<h3>验证签名</h3>
<pre><code class="language-java"> /**
* 验签
* @param content 报文
* @param sign 签名
* @param signKey 密钥
* @return 验签结果
* @throws Exception
*/
public static boolean verify(String content, String sign, String signKey) throws Exception {
String signStr = Md5Utils.digest(String.format("%s%s", content, signKey)).toUpperCase();
return Objects.equals(sign, signStr);
}</code></pre>
<h3>演示代码</h3>
<pre><code class="language-java">@PostMapping("/callback")
public String orderCallback(@RequestBody String paramJson, HttpServletRequest request) {
String signString = getSignString(getAuthHeaders(request), paramJson);
boolean verify = false;
try {
verify = verify(signString, request.getHeader("sign"), signKey);
} catch (Exception e) {
System.out.println("验签失败");
}
if (!verify) {
System.out.println("验签失败");
return "FAIL";
} else {
System.out.println("验签成功");
return "SUCCESS";
}
}
private Map<String, String> getAuthHeaders(HttpServletRequest request) {
Map<String, String> headerParams = new HashMap<>();
headerParams.put("businessId", request.getHeader("businessId"));
headerParams.put("nonce", request.getHeader("nonce"));
headerParams.put("timestamp", request.getHeader("timestamp"));
if (StringUtils.isNotBlank(request.getHeader("signType"))) {
headerParams.put("signType", request.getHeader("signType"));
}
return headerParams;
}
/**
* 构建待签名串
* @param headerParams 鉴权头数据
* @param dataJson 业务数据的JSON串
* @return 待签名串
*/
private String getSignString(Map<String, String> headerParams, String dataJson) {
String headerString = headerParams.keySet().stream()
.sorted()
.map(key -> key + "=" + headerParams.get(key))
.collect(Collectors.joining("&"));
return headerString + dataJson;
}
/**
* 验签
* @param content 报文
* @param sign 签名
* @param signKey 公钥
* @return 验签结果
* @throws Exception
*/
public static boolean verify(String content, String sign, String signKey) throws Exception {
String signStr = Md5Utils.digest(String.format("%s%s", content, signKey)).toUpperCase();
return Objects.equals(sign, signStr);
}</code></pre>