API网关计算签名的方法
<p><span style="font-size:18px"><strong>拼接签名内容</strong></span></p>
<p>API网关在计算签名前,需要按照以下格式生成签名原文:</p>
<table border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="background-color:#f7f8fa">
<p><span style="font-family:Consolas">String strToSign =<br />
HttpMethod + "\n" +<br />
URI + "\n" +<br />
Headers + "\n" +<br />
ContentDigest</span></p>
</td>
</tr>
</tbody>
</table>
<p><strong>拼接格式说明</strong>:</p>
<table border="1" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="background-color:#ededed; vertical-align:top; width:130px">
<p><strong>参数</strong></p>
</td>
<td style="background-color:#ededed; vertical-align:top; width:657px">
<p><strong>说明</strong></p>
</td>
</tr>
<tr>
<td style="vertical-align:top; width:130px">
<p>HttpMethod</p>
</td>
<td style="vertical-align:top; width:657px">
<p>API的调用方法,如GET、POST等。</p>
</td>
</tr>
<tr>
<td style="vertical-align:top; width:130px">
<p>URI</p>
</td>
<td style="vertical-align:top; width:657px">
<p>API的请求路径,格式为Path + Query:</p>
<p><span style="font-family:Consolas">...</span></p>
<p><span style="font-family:Consolas">String url =<br />
Path +<br />
"?" +<br />
Key1 + "=" + Value1 +<br />
"&" + Key2 + "=" + Value2 +<br />
...<br />
"&" + KeyN + "=" + ValueN;</span></p>
<p><span style="font-family:Consolas">...</span></p>
<p>其中:</p>
<p>• Path:如果有非法字符,例如:中文等,需要根据 Percent-Encoding使用UTF-8字符集对其进行编码。</p>
<p>• Query:先对参数的名称即Key按照字典顺序排序,再按照如下方法进行拼接:</p>
<p> ♦ 如果参数为空,则 URL = Path,不需要添加<span style="font-family:Arial,Helvetica,sans-serif">"?"</span>。</p>
<p> ♦ 如果某个参数的Value为空,则只保留参数的Key参与计算签名,等号 = 不需要再加入签名。</p>
<p> ♦ 如果某个参数的Value存在多个,则多个Value需要按照<strong>字典顺序</strong>进行排序后参与签名计算。</p>
<p> 例如:<span style="font-family:Consolas">String url = "/some/path.html?key1=value1&key2=value2&key2=value3&key3"</span></p>
<p><img src="https://pcp-portal-sca.obs-cn-shenzhen.pinganyun.com/pcp-portal-sca/20193110093656-1c5f2d909a8d.png" style="height:26px; margin:0px; width:65px" />:Query中参数的Key和Value是未进行URLEncoding的原数据。</p>
</td>
</tr>
<tr>
<td style="vertical-align:top; width:130px">
<p>Headers</p>
</td>
<td style="vertical-align:top; width:657px">
<p>由参与签名计算的请求头中参数的Key、Value拼接而成的字符串。参与签名计算的请求头包括:PA-AG-Gateway-Timestamp以及PA-AG-Gateway-Signature-Headers。</p>
<p><!--[if gte mso 9]><xml>
<o:OLEObject Type="Embed" ProgID="PBrush" ShapeID="_x0000_i1026"
DrawAspect="Content" ObjectID="_1633965004">
</o:OLEObject>
</xml><![endif]--><img src="https://pcp-portal-sca.obs-cn-shenzhen.pinganyun.com/pcp-portal-sca/20193010175017-19e172309ca6.png" style="height:26px; margin:0px; width:65px" />:请求头不区分大小写。</p>
<p>Headers拼接方式:</p>
<p>先对参与签名计算的请求头中参数的 Key 按照字典顺序排序,再按照如下方式进行拼接:</p>
<p>• 如果请求头中某个参数的Value为空,则使用HeaderKey.toLowercase() + ":"参与签名,需要保留Key和英文冒号<span style="font-family:Consolas">":"</span>,并且Key和Value左右两边不能有空白字符。</p>
<p>• 如果请求头中某个参数的Value存在多个,多个Value需要按照字典顺序进行排序后参与签名计算。</p>
<p>例如:</p>
<p><span style="font-family:Consolas">...</span></p>
<p><span style="font-family:Consolas">String headers =<br />
HeaderKey1.toLowercase() + ":" + HeaderValue1.toLowercase() + "\n"\+<br />
HeaderKey2.toLowercase() + ":" + HeaderValue2.toLowercase() + "\n"\+<br />
...<br />
HeaderKeyN.toLowercase() + ":" + HeaderValueN.toLowercase() + "\n"</span></p>
<p><span style="font-family:Consolas">...</span></p>
</td>
</tr>
<tr>
<td style="vertical-align:top; width:130px">
<p>ContentDigest</p>
</td>
<td style="vertical-align:top; width:657px">
<p>请求体的MD5值。</p>
<p>存在请求体时,需要对请求体进行MD5转码。</p>
<p>计算方式:</p>
<p><span style="font-family:Consolas">String contentDigest = Base64.encodeBase64(MD5(requestBody.getbytes("UTF-8")));</span></p>
</td>
</tr>
</tbody>
</table>
<p><span style="font-size:18px"><strong>生成签名结果</strong></span></p>
<p>API网关生成签名原文后,通过签名密钥,按照设置的签名算法进行签名计算。</p>
<p><strong>签名计算方法:</strong></p>
<table border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="background-color:#f7f8fa">
<p><span style="font-family:Consolas">Mac hmacSha256 = Mac.getInstance("HmacSHA256");<br />
byte[] keyBytes = secret.getBytes("UTF-8");<br />
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));<br />
String sign = new String(Base64.encodeBase64(hmacSha256.doFinal(strToSign.getBytes("UTF-8")),"UTF-8"));</span></p>
</td>
</tr>
</tbody>
</table>
<p>其中:</p>
<p>• secret:是绑定到API上的签名密钥的Secret。</p>
<p>• 签名算法:是创建API时选择的签名算法类型,目前支持HmacSHA1和HmacSHA256两种。</p>
<p><span style="font-size:18px"><strong>传递签名结果</strong></span></p>
<p>按照设置的签名算法进行签名计算后,API网关将签名结果放到PA-AG-Gateway-Signature字段中,并将在计算过程中所使用的签名密钥的Key放到PA-AG-Gateway-Sign-Key字段中。</p>
提交成功!非常感谢您的反馈,我们会继续努力做到更好!