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、签名生成方法

  1. 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签名类:

  1. package com.uc.meg.wpk.openapi.util;
  2. import java.util.Map;
  3. import java.util.Map.Entry;
  4. import java.util.TreeMap;
  5. import lombok.Data;
  6. import org.apache.commons.codec.digest.DigestUtils;
  7. import org.apache.commons.lang3.StringUtils;
  8. /**
  9. * 功能描述:签名builder
  10. * @version v1.0.0
  11. * @create on: 2018/4/9
  12. */
  13. @Data
  14. public class SignBuilder {
  15. private Map<String, String> params = new TreeMap<>();
  16. // json body
  17. private String body;
  18. private String clientId;
  19. private String secret;
  20. private Long timestamp;
  21. // 旧版1.0用的是随机串,并且不校验时常
  22. private String nonce;
  23. public SignBuilder params (Map<String, String> params) {
  24. this.params.clear();
  25. this.params.putAll(params);
  26. return this;
  27. }
  28. public SignBuilder addParam(String name, String value) {
  29. params.put(name, value);
  30. return this;
  31. }
  32. public SignBuilder body (String body) {
  33. this.addParam("body", body);
  34. return this;
  35. }
  36. public SignBuilder clientId(String clientId) {
  37. this.clientId = clientId;
  38. return this;
  39. }
  40. public SignBuilder secret(String secret) {
  41. this.secret = secret;
  42. return this;
  43. }
  44. public SignBuilder timestamp(Long timestamp) {
  45. this.timestamp = timestamp;
  46. return this;
  47. }
  48. public SignBuilder nonce(String nonce) {
  49. this.nonce = nonce;
  50. return this;
  51. }
  52. /**
  53. * 构建签名信息
  54. * @return
  55. */
  56. public String buildSign() {
  57. StringBuilder singBuilder = new StringBuilder(clientId).append(secret).append(timestamp);
  58. singBuilder.append(this.buildParams());
  59. return DigestUtils.md5Hex(singBuilder.toString());
  60. }
  61. /**
  62. * 拼接请求参数
  63. * @return
  64. */
  65. private StringBuilder buildParams () {
  66. StringBuilder rst = new StringBuilder();
  67. for (Entry<String, String> entry : params.entrySet()) {
  68. if (StringUtils.isBlank(entry.getKey())) {
  69. continue;
  70. }
  71. if (null == entry.getValue()) {
  72. rst.append(entry.getKey()).append("=");
  73. } else {
  74. String value = entry.getValue();
  75. rst.append(entry.getKey()).append("=").append(value);
  76. }
  77. }
  78. return rst;
  79. }
  80. }

4、签名获取示例:

  1. /**
  2. * 签名验证,以创建app的/rest/v1/api/app/create接口为例
  3. */
  4. /**
  5. * 签名
  6. */
  7. @Test
  8. public void testCreateApp() {
  9. String clientId = "clientId";
  10. String secert = "12345678901234567890";
  11. Long timestamp = 1526432218000L;
  12. Map<String, String> map = new HashMap<>();
  13. map.put("app", "wpktest20181031");
  14. map.put("name", "wpktest");
  15. map.put("type", "html5");
  16. map.put("src", "h5");
  17. map.put("aggType", "url");
  18. map.put("accessType", "jssdk");
  19. map.put("description", "测试联调");
  20. String jsonBody = ObjectMapperUtil.toJSONString(map);
  21. SignBuilder signBuilder = new SignBuilder();
  22. String sign = signBuilder.body(jsonBody).clientId(clientId).secret(secert).timestamp(timestamp).buildSign();
  23. System.out.println(sign);
  24. // 正确的签名:5de415bed120dfcd1e3c4f8616444719
  25. String url = host + "/rest/v1/api/app/create?clientId=clientId&timestamp=1526432218000&signature=5de415bed120dfcd1e3c4f8616444719"
  26. // sendRequestUseRestTemplate(url, jsonBody)
  27. // sendRequestUseHttpClient(url, jsonBody)
  28. }
  29. /**
  30. * 使用 restTemplate的发送请求
  31. *
  32. * @param url
  33. * @param reqBody
  34. */
  35. public String sendRequestUseRestTemplate(String url, String reqBody) {
  36. HttpHeaders headers = new HttpHeaders();
  37. headers.setContentType(MediaType.APPLICATION_JSON);
  38. HttpEntity<String> reqEntity = new HttpEntity<>(reqBody, headers);
  39. ResponseEntity<String> retEntity = restTemplate.postForEntity(url, reqEntity, String.class);
  40. return retEntity.getBody();
  41. }
  42. /**
  43. * 使用原生httpclient发送请求
  44. * @param url
  45. * @param jsonBody
  46. * @return
  47. * @throws IOException
  48. */
  49. public String sendRequestUseHttpClient(String url, String jsonBody) throws IOException {
  50. CloseableHttpClient httpClient = HttpClients.createDefault();
  51. HttpPost httpPost = new HttpPost(url);
  52. httpPost.addHeader("Content-Type", "application/json");
  53. httpPost.setEntity(new StringEntity(jsonBody));
  54. CloseableHttpResponse response = httpClient.execute(httpPost);
  55. org.apache.http.HttpEntity entity = response.getEntity();
  56. String responseContent = EntityUtils.toString(entity, "UTF-8");
  57. response.close();
  58. httpClient.close();
  59. return responseContent;
  60. }

得到签名后,需要把签名信息,连同其它参数信息传递至对应访问接口中即可正常访问接口!

2、符号表

2.1、符号表上传

api url:

  1. 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:

  1. {
  2. "id": "8cbdbe8a-173c-466c-82a2-41be0c2ef0f9",
  3. "code": "200",
  4. "message": "OK",
  5. "data": 123, // 符号表的唯一id
  6. "error": null
  7. }

2.2、符号表提取状态查询

api url:

  1. GET: /rest/v1/api/symbol/status?id=xxx

request字段说明:

字段名 说明 示例 是否必填
id 上传符号表时返回的唯一id 123

response:

  1. {
  2. "id": "8cbdbe8a-173c-466c-82a2-41be0c2ef0f9",
  3. "code": "200",
  4. "message": "OK",
  5. "data": {
  6. "status": 1,
  7. "msg": "完成处理"
  8. },
  9. "error": null
  10. }
  11. 返回值status字段说明:
  12. 1:完成处理; 2:正在上传; 3:等待处理; 4:正在处理; 5:处理失败; -1:符号表ID不存在

3、创建版本(只创建版本,不上传符号表)

api url:

  1. POST: /rest/v1/api/version/save?clientId=xxx

request:

  1. // post json
  2. {
  3. "app": "test",// 必填,对应的应用唯一标识(bid,appid)
  4. "version": "12.1.1.992(xxxx)", // 必填,版本 如:12.1.1.992(xxxx)
  5. "subVerSuffix": "test", // 子版本
  6. "parseenddate": "20190117", // 必填,解析结束时间 如:20191207
  7. "remark": "测试",// 说明
  8. }

response:

  1. {
  2. "id": "fd8d79bb-d5f7-4585-a2c3-68aefce7460b",
  3. "code": 200,
  4. "message": "OK",
  5. "data": {
  6. "id": 115421,
  7. "platform": "test",
  8. "version": "12.1.1.992(xxxx)",
  9. "appName": "12_1_1test",
  10. "sver": null,
  11. "tag": null,
  12. "coretag": null,
  13. "remark": "测试",
  14. "publishdate": "2018-08-17 00:00:00",
  15. "parseenddate": "20190117",
  16. "logtype": null,
  17. "ismonitor": 0,
  18. "currentparsingminute": null,
  19. "priority": 1,
  20. "deltaparseminute": null,
  21. "isparse": 1,
  22. "ispush": 0,
  23. "pushmaillist": null,
  24. "pushhour": null,
  25. "pushdays": null,
  26. "monitorrules": null,
  27. "uploadSymbolDate": null,
  28. "uploadSymbolBy": null,
  29. "uploadSymbolByName": null,
  30. "createAt": "2019-01-17 14:26:55",
  31. "createBy": null,
  32. "updateAt": "2019-01-17 14:26:55",
  33. "updateBy": null,
  34. "parseStatus": 0,
  35. "subVerSuffix": "test"
  36. },
  37. "error": null
  38. }

code说明:
200,正常返回
其它,系统异常,可参照error中的type下message

4. 上传符号表示例脚本

api_wpktuils.py.zip