1、签名验证说明
1、网络环境
环境 | 域名 |
---|---|
线上环境 | https://wpk.uc.cn |
2、HTTP 提交数据说明
除了特殊说明接口外当 POST, PUT 请求的时候,请确保 Request Content-Type是 application/json
类型。
3、签名验证协议 1)、签名公共参数说明
名称 | 是否必须 | 描述 | 来源 |
---|---|---|---|
clientId | 是 | 应用标识 | 首次访问可联系技术人员获取 |
secret | 是 | 应用秘钥 | 首次访问可联系技术人员获取 |
timestamp | 是 | 请求时间戳 从 1970 年 1 月 1 日开始计算到现在的毫秒数 | 调用时客户端自行生成 |
4、公共参数
名称 | 描述 | 是否必填 | 传参位置 |
---|---|---|---|
clientId | 应用标识 | 是 | url |
timestamp | 时间戳 | 是 | url |
signature | 签名参数 | 是 | url |
4、签名生成方法
signStr = MD5(clientId+secret+timestamp+k1=v1+k2=v2+...+kn=vn+body={})
说明:
- MD5 使用RFC 1321 规范
- 表达式中的“+”号表示字符串接,实际并不存在。
- 业务参数按(除了公共签名参数外所有参数,如k1=v1)按排序树排序
- body={}标识post&put等请求中带有json body时的处理方式,即:key=body,value= Request Body 字符串
- 签名有效期5分钟
5、java签名类:
package com.uc.meg.wpk.openapi.util;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import lombok.Data;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
/**
* 功能描述:签名builder
* @version v1.0.0
* @create on: 2018/4/9
*/
@Data
public class SignBuilder {
private Map<String, String> params = new TreeMap<>();
// json body
private String body;
private String clientId;
private String secret;
private Long timestamp;
// 旧版1.0用的是随机串,并且不校验时常
private String nonce;
public SignBuilder params (Map<String, String> params) {
this.params.clear();
this.params.putAll(params);
return this;
}
public SignBuilder addParam(String name, String value) {
params.put(name, value);
return this;
}
public SignBuilder body (String body) {
this.addParam("body", body);
return this;
}
public SignBuilder clientId(String clientId) {
this.clientId = clientId;
return this;
}
public SignBuilder secret(String secret) {
this.secret = secret;
return this;
}
public SignBuilder timestamp(Long timestamp) {
this.timestamp = timestamp;
return this;
}
public SignBuilder nonce(String nonce) {
this.nonce = nonce;
return this;
}
/**
* 构建签名信息
* @return
*/
public String buildSign() {
StringBuilder singBuilder = new StringBuilder(clientId).append(secret).append(timestamp);
singBuilder.append(this.buildParams());
return DigestUtils.md5Hex(singBuilder.toString());
}
/**
* 拼接请求参数
* @return
*/
private StringBuilder buildParams () {
StringBuilder rst = new StringBuilder();
for (Entry<String, String> entry : params.entrySet()) {
if (StringUtils.isBlank(entry.getKey())) {
continue;
}
if (null == entry.getValue()) {
rst.append(entry.getKey()).append("=");
} else {
String value = entry.getValue();
rst.append(entry.getKey()).append("=").append(value);
}
}
return rst;
}
}
4、签名获取示例:
/**
* 签名验证,以创建app的/rest/v1/api/app/create接口为例
*/
/**
* 签名
*/
@Test
public void testCreateApp() {
String clientId = "clientId";
String secert = "12345678901234567890";
Long timestamp = 1526432218000L;
Map<String, String> map = new HashMap<>();
map.put("app", "wpktest20181031");
map.put("name", "wpktest");
map.put("type", "html5");
map.put("src", "h5");
map.put("aggType", "url");
map.put("accessType", "jssdk");
map.put("description", "测试联调");
String jsonBody = ObjectMapperUtil.toJSONString(map);
SignBuilder signBuilder = new SignBuilder();
String sign = signBuilder.body(jsonBody).clientId(clientId).secret(secert).timestamp(timestamp).buildSign();
System.out.println(sign);
// 正确的签名:5de415bed120dfcd1e3c4f8616444719
String url = host + "/rest/v1/api/app/create?clientId=clientId×tamp=1526432218000&signature=5de415bed120dfcd1e3c4f8616444719"
// sendRequestUseRestTemplate(url, jsonBody)
// sendRequestUseHttpClient(url, jsonBody)
}
/**
* 使用 restTemplate的发送请求
*
* @param url
* @param reqBody
*/
public String sendRequestUseRestTemplate(String url, String reqBody) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> reqEntity = new HttpEntity<>(reqBody, headers);
ResponseEntity<String> retEntity = restTemplate.postForEntity(url, reqEntity, String.class);
return retEntity.getBody();
}
/**
* 使用原生httpclient发送请求
* @param url
* @param jsonBody
* @return
* @throws IOException
*/
public String sendRequestUseHttpClient(String url, String jsonBody) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json");
httpPost.setEntity(new StringEntity(jsonBody));
CloseableHttpResponse response = httpClient.execute(httpPost);
org.apache.http.HttpEntity entity = response.getEntity();
String responseContent = EntityUtils.toString(entity, "UTF-8");
response.close();
httpClient.close();
return responseContent;
}
得到签名后,需要把签名信息,连同其它参数信息传递至对应访问接口中即可正常访问接口!
2、符号表
2.1、符号表上传
api url:
POST: /rest/v1/api/symbol/upload
content-type: multipart/form-data;
request字段说明:
字段名 | 说明 | 示例 | 是否必填 |
---|---|---|---|
clientId | 调用方的clientId | 是 | |
app | 应用标识 | mobile/IPhXXX | 是 |
version | 版本号(若版本不存在,会为其创建该版本) | 12.1.0.12、12.1.0.12(123456) | 是 |
symbolType | 类型,测试版传test、正式版传release | test、release | 是 |
file | 符号文件,使用zip压缩 | 是 |
response:
{
"id": "8cbdbe8a-173c-466c-82a2-41be0c2ef0f9",
"code": "200",
"message": "OK",
"data": 123, // 符号表的唯一id
"error": null
}
2.2、符号表提取状态查询
api url:
GET: /rest/v1/api/symbol/status?id=xxx
request字段说明:
字段名 | 说明 | 示例 | 是否必填 |
---|---|---|---|
id | 上传符号表时返回的唯一id | 123 | 是 |
response:
{
"id": "8cbdbe8a-173c-466c-82a2-41be0c2ef0f9",
"code": "200",
"message": "OK",
"data": {
"status": 1,
"msg": "完成处理"
},
"error": null
}
返回值status字段说明:
1:完成处理; 2:正在上传; 3:等待处理; 4:正在处理; 5:处理失败; -1:符号表ID不存在
3、创建版本(只创建版本,不上传符号表)
api url:
POST: /rest/v1/api/version/save?clientId=xxx
request:
// post json
{
"app": "test",// 必填,对应的应用唯一标识(bid,appid)
"version": "12.1.1.992(xxxx)", // 必填,版本 如:12.1.1.992(xxxx)
"subVerSuffix": "test", // 子版本
"parseenddate": "20190117", // 必填,解析结束时间 如:20191207
"remark": "测试",// 说明
}
response:
{
"id": "fd8d79bb-d5f7-4585-a2c3-68aefce7460b",
"code": 200,
"message": "OK",
"data": {
"id": 115421,
"platform": "test",
"version": "12.1.1.992(xxxx)",
"appName": "12_1_1test",
"sver": null,
"tag": null,
"coretag": null,
"remark": "测试",
"publishdate": "2018-08-17 00:00:00",
"parseenddate": "20190117",
"logtype": null,
"ismonitor": 0,
"currentparsingminute": null,
"priority": 1,
"deltaparseminute": null,
"isparse": 1,
"ispush": 0,
"pushmaillist": null,
"pushhour": null,
"pushdays": null,
"monitorrules": null,
"uploadSymbolDate": null,
"uploadSymbolBy": null,
"uploadSymbolByName": null,
"createAt": "2019-01-17 14:26:55",
"createBy": null,
"updateAt": "2019-01-17 14:26:55",
"updateBy": null,
"parseStatus": 0,
"subVerSuffix": "test"
},
"error": null
}
code说明:
200,正常返回
其它,系统异常,可参照error中的type下message