## 接口描述 接口的通讯报文采用 Http请求正文格式,系统提供通过服务器调用的形式调用接口的能力 **商家端、平台端**:第三方服务器调用的接口和商家/平台直接登录进行调用的接口是一样的。我们通过签名验签的方式代替了商家/平台直接登录的形式。 **用户端**:第三方服务器通过调用系统提供的四个签名验签的接口向系统注册用户、将第三方token同步到系统中,后面就可以通过传递token形式调用用户端其他接口(具体查看下面用户端对接介绍) #### 功能支持 - websocket接口不支持 - 无需授权的接口不支持,具体参考DefaultAuthConfigAdapter里面的set 密钥分不同的系统类型访问类型,分为商家,平台,用户。其中商家和平台细分了菜单权限, 且商家密钥有全部商家和指定商家访问的细分。 ## 商家端、平台端对接 **商家端、平台端接口均采用签名的方式调用** ### 接口报文结构及报文与签名生成 为了区分服务器调用还是普通的用户调用,需要携带请求头“grantType = sign”,grantType这个参数是Oauth2.0协议当中用来确定授权方式的,系统也利用同样的词汇来区分是否为签名验证的用户。同时根据http请求的content-type 不同,如果是application/json这种形式的,json的数据将会被data包裹(通常是post、put、delete请求)。如果只是普通的get请求或图片上传等请求,那么请求的数据不需要被包裹 ### 接口报文规范 #### POST、PUT、DELETE 请求格式说明 ##### 请求头(Header) | 字段元素 | 类型 | 是否必填 | 说明 | | :----------: | :----: | :--------: | :---------------------------------------------------------: | | grantType | String | 是 | 固定为:sign | | Content-Type | String | 是 | 固定为:application/json | ##### 请求参数 | 字段元素 | 类型 | 是否必填 | 说明 | | :----: | :---: | :---: | :---: | | appId | String | 是 | 分配给应用的系统密钥id | | timestamp | Long | 是 | 请求的时间戳,接入系统的时间误差不能超过 10 分钟,毫秒 | | sign | String | 是 | 签名,通过签名机制,防止应用的请求参数被非法篡改,业务系统必须保证该值不被泄露。 | | data | Object | 是 | 真正请求的数据(当且仅当content-type是application/json的时候,将真正的数据放入data) | 为了方便起见,以下所有涉及到签名的,我们使用一个演示签名用的appId和appSecret appId: appId123456 appSecret: appSecret123456 ##### data参数构成 | 字段元素 | 类型 | 必填条件 | 说明 | |:----------:|:-------:|:-----------:|:--------------------------------:| | sysType | String | 是 | 0.用户端 1.商家端 2.平台端 3.供应商端 4.自提门店端 | | userId | String | 否 | 调用用户端接口时必填,用户id,用于定位到具体的用户 | | shopId | String | 否 | 调用商家端接口时必填,商家店铺id,用于定位到具体的店铺 | | supplierId | String | 否 | 调用供应商端接口时必填,供应商店铺id,用于定位到具体的供应商 | | stationId | String | 否 | 调用自提门店端接口时必填,自提门店id,用于定位到具体的自提点 | | sysUserId | String | 否 | 调用平台端接口时必填,平台管理员的账号id,用于定位到具体的管理员账号 | | 其他请求参数 | | | 接口的实际请求参数 | | ##### 下面以平台端新增热搜接口来做一个实例讲解: ![img.png](../img/基本开发文档/第三方接口对接协议/平台新增热搜接口文档.png) 接口地址为:/tmerclub_admin/mp/hot_search 接口请求参数为: ``` { "hotSearchId": 0, "shopId": 0, "title": "", "content": "", "recDate": "", "seq": 0, "status": 0 } ``` 实际的请求格式为: ``` curl --location --request POST 'http://localhost:8000/tmerclub_admin/mp/hot_search' \ --header 'grantType: sign' \ --header 'Content-Type: application/json' \ --data-raw '{ "appSecret": "appSecret123456", "timestamp":1683169451230, "data":{ "sysType": 2, "sysUserId": 1, "hotSearchId": 0, "title": "热搜标题", "content": "热搜内容", "seq": 0, "status": 1, "type": 1 }, "sign":"d724ced82e8d098461a7fefd5e4db8fa20acbc890d7facb9941b58b6158e75ba" }' ``` appId:分配给应用的系统密钥id timestamp: 请求的时间戳,根据当前时间生成 sign: 签名,使用该请求参数生成,生成流程在下面有说明 data.userId : 此次请求使用平台端id为1的管理员账号进行操作 其他data参数为接口的参数 以上就是一个post请求的全部数据了 ###### sign(签名)的生成流程: 1. 拼接json数据,生成post请求签名用到的参数有 appSecret、timestamp和data,具体实例为: ``` { "appSecret": "appSecret123456", "timestamp": "1683169451230", "data":{ "sysType": 2, "sysUserId": 1, "hotSearchId": 0, "title": "热搜标题", "content": "热搜内容", "seq": 0, "status": 1, "type": 1 } } ``` 2. 对json参数重新进行排序,根据key的值按顺序进行排序,排序后的数据格式为: ``` { "appSecret": "appSecret123456", "data": { "content": "热搜内容", "seq": 0, "status": 1, "sysType": "2", "sysUserId": "1", "title": "热搜标题", "type": 1 }, "timestamp": "1683169451230" } ``` 3. 通过sha256的形式进行签名, 签名结果为:d724ced82e8d098461a7fefd5e4db8fa20acbc890d7facb9941b58b6158e75ba ![img.png](../img/基本开发文档/第三方接口对接协议/POST-SHA256.png) 在线加密地址: ##### java代码示例 ```java /** * 新增热搜接口 */ public static void main(String[] args) { // +++++++++++++++++++++++++++++++++ 组装post请求数据 +++++++++++++++++++++++++++++++++ long timestamp = System.currentTimeMillis(); // 实际的接口数据 TreeMap dataMap = new TreeMap<>(); dataMap.put("content","热搜内容"); dataMap.put("seq", 0); dataMap.put("type", 1); dataMap.put("status", 1); dataMap.put("title","热搜标题"); // 平台账号id dataMap.put("sysUserId", "1"); dataMap.put("sysType", "2"); TreeMap(); param.put("timestamp", String.valueOf(timestamp)); param.put("appSecret", "appSecret123456"); param.put("data", dataMap); // 签名 Digester sha256 = new Digester(DigestAlgorithm.SHA256); String sign = sha256.digestHex(Json.toJsonString(param)); // 添加签名和账号id param.put("sign", sign); param.put("appId", "appId123456"); // +++++++++++++++++++++++++++++++++ 发送post请求 +++++++++++++++++++++++++++++++++ String result = HttpRequest.post("http://localhost:8000/tmerclub_admin/mp/hot_search") .header("grantType","sign") .header("Accept", "*/*") .header("Content-Type","application/json") .body(Json.toJsonString(param)) .execute().body(); System.out.println(result); // +++++++++++++++++++++++++++++++++ 响应数据验签 +++++++++++++++++++++++++++++++++ // 结果验签 TreeMap(); map.put("appSecret", "appSecret123456"); map.put("data", responseMap.get("data")); map.put("timestamp", responseMap.get("timestamp")); // 验签 if (Objects.equals(responseMap.get("sign").toString(), sha256.digestHex(Json.toJsonString(map)))) { System.out.println("success"); } } ``` #### GET请求格式说明 ##### 请求头(Header) | 字段元素 | 类型 | 是否必填 | 说明 | | :----------: | :----: | :--------: | :---------------------------------------------------------: | | grantType | String | 是 | 固定为:sign | | Accept | String | 是 | 固定为:*/* | ##### 请求参数 | 字段元素 | 类型 | 是否必填 | 说明 | | :----: | :---: |:----:|:----------------------------------------:| | appId | String | 是 | 分配给应用的系统密钥id | | timestamp | Long | 是 | 请求的时间戳,接入系统的时间误差不能超过 10 分钟,毫秒 | | sign | String | 是 | 签名,通过签名机制,防止应用的请求参数被非法篡改,业务系统必须保证该值不被泄露。 | | sysType | String | 是 | 0.用户端 1.商家端 2.平台端 3.供应商端 4.自提门店端 | | userId | String | 否 | 调用用户端接口时必填,用户id,用于定位到具体的用户 | | shopId | String | 否 | 调用商家端接口时必填,商家店铺id,用于定位到具体的店铺 | | supplierId | String | 否 | 调用供应商端接口时必填,供应商店铺id,用于定位到具体的供应商 | | stationId | String | 否 | 调用自提门店端接口时必填,自提门店id,用于定位到具体的自提点 | | sysUserId | String | 否 | 调用平台端接口时必填,平台管理员的账号id,用于定位到具体的管理员账号 | | 其他请求参数 | | | 接口的实际请求参数 | #### ##### 下面以平台端商品搜索接口来做一个实例讲解: ![img.png](../img/基本开发文档/第三方接口对接协议/平台商品搜索接口文档.png) 接口地址为:/tmerclub_search/p/search/page 接口请求参数为: ``` current = 1 size = 10 ``` 实际的请求格式为: ``` curl --location --request GET 'http://localhost:8000/tmerclub_search/p/search/page?sysType=2&sysUserId=1&appSecret=appSecret123456&pageNum=1&pageSize=10&appId=appId123456&sign=512ab86bc78b035c2c02570d0b01560cad36f64be9943fbe6a5d9dcd916a8d2e×tamp=1683167795211' \ --header 'grantType: sign' ``` appId:分配给应用的系统密钥id timestamp: 请求的时间戳,根据当前时间生成 userId: 此次请求使用平台端id为1的管理员账号进行操作 sign: 签名,使用该请求参数生成,生成流程在下面有说明 current : 请求接口的参数,查询分页为1的数据 size: 请求接口的参数,每页数据大小为10 以上就是一个get请求的全部数据了 ##### sign(签名)的生成流程: 1.拼接json数据,生成get请求签名用到的参数有 appSecret、timestamp和接口中的参数,具体实例为: 注意:get请求的sign获取数据跟post请求相同都是json,不同的是value的值必须是字符串 ``` { "appSecret": "appSecret123456", "timestamp": "1683167795211", "sysType": "2", "sysUserId": "1", "pageNum ": "1", "pageSize": "10" } ``` 2.对json参数重新进行排序,根据key的值按顺序进行排序,排序后的数据格式为: ``` { "appSecret": "appSecret123456", "pageNum ": "1", "pageSize": "10", "sysType": "2", "sysUserId": "1", "timestamp": "1683167795211" } ``` 3. 通过sha256的形式进行签名, 签名结果为:389d3f8297214d66cd60effb012541eee752cf48f0022d123ebbdaa03fd7ba81 ![img.png](../img/基本开发文档/第三方接口对接协议/GET-SHA256.png) 在线加密地址: ##### java代码示例 ```java /** * 查询商品接口 */ public static void main(String[] args) { // +++++++++++++++++++++++++++++++++ 组装get请求数据 +++++++++++++++++++++++++++++++++ long timestamp = System.currentTimeMillis(); TreeMap param = new TreeMap<>(); // 平台账号id param.put("sysType", "2"); param.put("sysUserId", "1"); param.put("timestamp", String.valueOf(timestamp)); param.put("appSecret", "appSecret123456"); // 接口请求参数 param.put("pageNum", "1"); param.put("pageSize", "10"); // 签名 Digester sha256 = new Digester(DigestAlgorithm.SHA256); String sign = sha256.digestHex(Json.toJsonString(param)); // 添加签名和账号id param.put("sign", sign); param.put("appId","appId123456"); // +++++++++++++++++++++++++++++++++ 发送get请求 +++++++++++++++++++++++++++++++++ String result = HttpRequest.get("http://localhost:8000/tmerclub_search/p/search/page") .header("grantType","sign") .header("Accept", "*/*") .form(param) .execute().body(); System.out.println(result); // +++++++++++++++++++++++++++++++++ 响应数据验签 +++++++++++++++++++++++++++++++++ // 结果验签 TreeMap(); map.put("appSecret", "appSecret123456"); map.put("data", responseMap.get("data")); map.put("timestamp", responseMap.get("timestamp")); // 验签 if (Objects.equals(responseMap.get("sign").toString(), sha256.digestHex(Json.toJsonString(map)))) { System.out.println("success"); } } ``` ## **用户端对接** **用户端提供四个用签名验签方式调用的接口** - 注册用户接口 - 将用户token以及过期时间同步到商城接口 - 修改用户名称接口 - 禁用用户接口 通过注册用户(调用注册用户接口)、将token同步到系统中(调用将用户token以及过期时间同步到商城接口),既可正常请求用户端其他接口(请求头传递token形式) ### 用签名验签方式调用的接口报文结构及报文与签名生成 为了区分服务器调用还是普通的用户调用,需要携带请求头“grantType = sign”,grantType这个参数是Oauth2.0协议当中用来确定授权方式的,系统也利用同样的词汇来区分是否为签名验证的用户。同时根据http请求的content-type 不同,如果是application/json这种形式的,json的数据将会被data包裹(通常是post、put、delete请求)。如果只是普通的get请求或图片上传等请求,那么请求的数据不需要被包裹 ### 接口报文规范 #### POST、PUT 请求格式说明 ##### 请求头(Header) | 字段元素 | 类型 | 是否必填 | 说明 | | :----------: | :----: | :--------: | :---------------------------------------------------------: | | grantType | String | 是 | 固定为:sign | | Content-Type | String | 是 | 固定为:application/json | ##### 请求参数 | 字段元素 | 类型 | 是否必填 | 说明 | | :----: | :---: | :---: | :---: | | appId | String | 是 | 分配给应用的系统密钥id | | timestamp | Long | 是 | 请求的时间戳,接入系统的时间误差不能超过 10 分钟,毫秒 | | sign | String | 是 | 签名,通过签名机制,防止应用的请求参数被非法篡改,业务系统必须保证该值不被泄露。 | | data | Object | 是 | 真正请求的数据(当且仅当content-type是application/json的时候,将真正的数据放入data) | 下面四个涉及签名的接口,这里我是用一个演示的用户端签名 appId: 167633802736 appSecret:3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764 ### 注册用户接口 #### data参数构成 | 字段元素 | 类型 | 必填条件 | 说明 | | :------: | :----: |:----:| :--------------------------------------------: | | userId | String | 必填 | 通信的用户唯一ID,可以随机uuid (建议自己服务端的用户唯一uid) | | nickName | String | 必填 | 用户昵称,商城有些通知会需要用到 | #### 调用演示 接口地址:/tmerclub_user/ua/server/user/register 请求类型:post 接口请求参数 ``` { "userId":"userId33", "nickName" : "注册用户" } ``` 实际的请求格式为: ``` curl --location --request POST 'http://localhost:8000/tmerclub_user/ua/server/user/register' \ --header 'grantType: sign' \ --header 'Content-Type: application/json' \ --data-raw '{     "appId":"167633802736",     "timestamp":1640761421949,     "data":{ "userId":"userId33", "nickName" : "注册用户" },     "sign":"bdb4bf1c63dada19901d7022e187d1558b1ce001c3ae53bb9b6ac37355a9bcbe" }' ``` appId:分配给应用的系统密钥id timestamp: 请求的时间戳,根据当前时间生成 sign: 签名,使用该请求参数生成,生成流程在下面有说明 data参数为接口的参数 以上就是一个post请求的全部数据了 #### sign(签名)的生成流程: 1.拼接json数据,生成post请求签名用到的参数有 appSecret、timestamp和data,具体实例为: ``` { "appSecret": "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764", "timestamp": "1640761421949", "data": { "userId":"userId33", "nickName" : "注册用户" } } ``` 2.对json参数重新进行排序,根据key的值按顺序进行排序,排序后的数据格式为: ``` { "appSecret": "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764", "data": { "userId":"userId33", "nickName" : "注册用户" }, "timestamp": "1640761421949" } ``` 3. 通过sha256的形式进行签名, 签名结果为:a034d64e38fe8db70053ac44187f788c5dde4bae839cdc42cf2c1e82247b726f ![image_2](../img/基本开发文档/第三方接口对接协议/image_1.png) 在线加密地址: #### java代码示例 ```java /** * 注册用户接口 * @param args */ public static void main(String[] args) { // +++++++++++++++++++++++++++++++++ 组装post请求数据 +++++++++++++++++++++++++++++++++ // 获取时间戳 Long timestamp = System.currentTimeMillis(); // 设置时间戳和密钥 TreeMap param = new TreeMap<>(); param.put("timestamp",timestamp.toString()); param.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); // 实际的接口数据 TreeMap dataMap = new TreeMap<>(); dataMap.put("userId", "userId33"); dataMap.put("nickName","注册用户"); param.put("data", dataMap); // 签名 Digester sha256 = new Digester(DigestAlgorithm.SHA256); String sysSign = sha256.digestHex(Json.toJsonString(param)); // 添加签名和账号id param.put("sign" , sysSign); param.put("appId","167633802736"); String result = HttpRequest.post("http://localhost:8000/tmerclub_user/ua/server/user/register") .header("grantType","sign") .header("Content-Type","application/json") .body(JSONObject.toJSONString(param)) .execute().body(); // +++++++++++++++++++++++++++++++++ 响应数据验签 +++++++++++++++++++++++++++++++++ // 结果验签 TreeMap responseMap = JSONObject.parseObject(result, TreeMap.class); TreeMap map = new TreeMap<>(); map.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); map.put("data", responseMap.get("data")); map.put("timestamp", responseMap.get("timestamp")); // 验签 if (Objects.equals(responseMap.get("sign").toString(), sha256.digestHex(Json.toJsonString(map)))) { System.out.println("success"); } } ``` ### 将用户token以及过期时间同步到商城接口 #### data参数构成 | 字段元素 | 类型 | 必填条件 | 说明 | | :------: | :----: |:----:| :--------------------------------------------: | | userId | String | 必填 | 通信的用户唯一ID,可以随机uuid (建议自己服务端的用户唯一uid) | | accessToken | String | 必填 | 校验的token,随机uuid(建议使用自己服务端的用户的token) | | expiresIn| Long|必填|token在多少秒后过期| |openId|String|否|openId,如果当前是在小程序上,则传小程序的openid。如果是在微信浏览器上开打,则传公众号openid| |socialType|String|否|socialType, 1小程序登录,2公众号登录,0 其他| ### 调用演示 接口地址:/tmerclub_user/ua/server/user/token 请求类型:post 接口请求参数 ``` { "userId":"userId33", "accessToken" : "token_test", "expiresIn": "10000" "openId": "xxxxxx", "socialType": "1" } ``` 实际的请求格式为: ``` curl --location --request POST 'http://localhost:8000/tmerclub_user/ua/server/user/token' \ --header 'grantType: sign' \ --header 'Content-Type: application/json' \ --data-raw '{     "appId":"appId123456",     "timestamp":1640761421949,     "data":{ "userId":"userId33", "accessToken" : "token_test", "expiresIn": "10000" "openId": "xxxxxx", "socialType": "1" },     "sign":"bdb4bf1c63dada19901d7022e187d1558b1ce001c3ae53bb9b6ac37355a9bcbe" }' ``` appId:分配给应用的系统密钥id timestamp: 请求的时间戳,根据当前时间生成 sign: 签名,使用该请求参数生成,生成流程在下面有说明 data参数为接口的参数 ##### sign(签名)的生成流程(与注册用户接口一样) #### java代码示例 ```java /** * 将用户token以及过期时间同步到商城 * @param args */ public static void main(String[] args) { // +++++++++++++++++++++++++++++++++ 组装post请求数据 +++++++++++++++++++++++++++++++++ // 获取时间戳 Long timestamp = System.currentTimeMillis(); // 设置时间戳和密钥 TreeMap param = new TreeMap<>(); param.put("timestamp",timestamp.toString()); param.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); // 实际的接口数据 TreeMap dataMap = new TreeMap<>(); dataMap.put("userId", "userId33"); dataMap.put("accessToken","token_test"); dataMap.put("expiresIn",1000L); dataMap.put("openId","xxxxxxx"); dataMap.put("socialType","1"); param.put("data", dataMap); // 签名 Digester sha256 = new Digester(DigestAlgorithm.SHA256); String sysSign = sha256.digestHex(Json.toJsonString(param)); // 添加签名和账号id param.put("sign" , sysSign); param.put("appId","167633802736"); String result = HttpRequest.post("http://localhost:8000/tmerclub_user/ua/server/user/token") .header("grantType","sign") .header("Content-Type","application/json") .body(JSONObject.toJSONString(param)) .execute().body(); // +++++++++++++++++++++++++++++++++ 响应数据验签 +++++++++++++++++++++++++++++++++ // 结果验签 TreeMap responseMap = JSONObject.parseObject(result, TreeMap.class); TreeMap map = new TreeMap<>(); map.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); map.put("data", responseMap.get("data")); map.put("timestamp", responseMap.get("timestamp")); // 验签 if (Objects.equals(responseMap.get("sign").toString(), sha256.digestHex(Json.toJsonString(map)))) { System.out.println("success"); } } ``` ### 修改用户接口(用于修改用户昵称) #### data参数构成 | 字段元素 | 类型 | 必填条件 | 说明 | | :------: | :----: |:----:| :--------------------------------------------: | | userId | String | 必填 | 通信的用户唯一ID,可以随机uuid (建议自己服务端的用户唯一uid) | | nickName | String | 必填 | 用户昵称,商城有些通知会需要用到 | ### 调用演示 接口地址:/tmerclub_user/ua/server/user/update 请求类型:put 接口请求参数 ``` { "userId":"123", "nickName": "修改名称" } ``` 实际的请求格式为: ``` curl --location --request PUT 'http://localhost:8000/tmerclub_user/ua/server/user/token' \ --header 'grantType: sign' \ --header 'Content-Type: application/json' \ --data-raw '{     "appId":"167633802736",     "timestamp":1640761421949,     "data":{ "userId":"123", "nickName": "修改名称" },     "sign":"bdb4bf1c63dada19901d7022e187d1558b1ce001c3ae53bb9b6ac37355a9bcbe" }' ``` appId:分配给应用的系统密钥id timestamp: 请求的时间戳,根据当前时间生成 sign: 签名,使用该请求参数生成,生成流程在下面有说明 data参数为接口的参数 ##### sign(签名)的生成流程(与注册用户接口一样) #### java代码示例 ```java /** * 更新用户接口 * @param args */ public static void main(String[] args) { // +++++++++++++++++++++++++++++++++ 组装put请求数据 +++++++++++++++++++++++++++++++++ // 获取时间戳 Long timestamp = System.currentTimeMillis(); // 设置时间戳和密钥 TreeMap param = new TreeMap<>(); param.put("timestamp",timestamp.toString()); param.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); // 实际的接口数据 TreeMap dataMap = new TreeMap<>(); dataMap.put("userId", "userId33"); dataMap.put("nickName","修改名称"); param.put("data", dataMap); // 签名 Digester sha256 = new Digester(DigestAlgorithm.SHA256); String sysSign = sha256.digestHex(Json.toJsonString(param)); // 添加签名和账号id param.put("sign" , sysSign); param.put("appId","167633802736"); String result = HttpRequest.put("http://localhost:8000/tmerclub_user/ua/server/user/update") .header("grantType","sign") .header("Content-Type","application/json") .body(JSONObject.toJSONString(param)) .execute().body(); // +++++++++++++++++++++++++++++++++ 响应数据验签 +++++++++++++++++++++++++++++++++ // 结果验签 TreeMap responseMap = JSONObject.parseObject(result, TreeMap.class); TreeMap map = new TreeMap<>(); map.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); map.put("data", responseMap.get("data")); map.put("timestamp", responseMap.get("timestamp")); // 验签 if (Objects.equals(responseMap.get("sign").toString(), sha256.digestHex(Json.toJsonString(map)))) { System.out.println("success"); } } ``` ### 禁用用户接口 #### data参数构成 | 字段元素 | 类型 | 必填条件 | 说明 | | :------: | :----: |:----:| :--------------------------------------------: | | userId | String | 必填 | 通信的用户唯一ID,可以随机uuid (建议自己服务端的用户唯一uid) | ### 调用演示 接口地址:/tmerclub_user/ua/server/user/disable 请求类型:put 接口请求参数 ``` { "userId":"123", } ``` 实际的请求格式为: ``` curl --location --request PUT 'http://localhost:8000/tmerclub_user/ua/server/user/token' \ --header 'grantType: sign' \ --header 'Content-Type: application/json' \ --data-raw '{     "appId":"167633802736",     "timestamp":1640761421949,     "data":{ "userId":"123" },     "sign":"bdb4bf1c63dada19901d7022e187d1558b1ce001c3ae53bb9b6ac37355a9bcbe" }' ``` appId:分配给应用的系统密钥id timestamp: 请求的时间戳,根据当前时间生成 sign: 签名,使用该请求参数生成,生成流程在下面有说明 data参数为接口的参数 ##### sign(签名)的生成流程(与注册用户接口一样) #### java代码示例 ```java /** * 禁用用户接口 * @param args */ public static void main(String[] args) { // +++++++++++++++++++++++++++++++++ 组装put请求数据 +++++++++++++++++++++++++++++++++ // 获取时间戳 Long timestamp = System.currentTimeMillis(); // 设置时间戳和密钥 TreeMap param = new TreeMap<>(); param.put("timestamp",timestamp.toString()); param.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); // 实际的接口数据 TreeMap dataMap = new TreeMap<>(); dataMap.put("userId", "userId33"); param.put("data", dataMap); // 签名 Digester sha256 = new Digester(DigestAlgorithm.SHA256); String sysSign = sha256.digestHex(Json.toJsonString(param)); // 添加签名和账号id param.put("sign" , sysSign); param.put("appId","167633802736"); String result = HttpRequest.put("http://localhost:8000/tmerclub_user/ua/server/user/disable") .header("grantType","sign") .header("Content-Type","application/json") .body(JSONObject.toJSONString(param)) .execute().body(); // +++++++++++++++++++++++++++++++++ 响应数据验签 +++++++++++++++++++++++++++++++++ // 结果验签 TreeMap responseMap = JSONObject.parseObject(result, TreeMap.class); TreeMap map = new TreeMap<>(); map.put("appSecret", "3bf5e9951ee3406e109389a3118a6f7be15d0339b57dbe2a9db0b0a9149cdf131702370796764"); map.put("data", responseMap.get("data")); map.put("timestamp", responseMap.get("timestamp")); // 验签 if (Objects.equals(responseMap.get("sign").toString(), sha256.digestHex(Json.toJsonString(map)))) {System.out.println("success"); } } ``` ### 调用用户端其他接口演示 **前提:已经注册用户(调用注册用户接口)、并且将token同步到系统中(调用将用户token以及过期时间同步到商城接口)** 下面我将通过一个获取用户详情接口(无请求参数)演示 **请求头token:** 拿上面已经同步到系统的接口token_test **接口请求参数:** 具体参数查看接口文档,封装好参数即可 ![image](../img/基本开发文档/第三方接口对接协议/image.png) #### java代码示例 ```java /** * 获取用户详情接口 * @param args */ public static void main(String[] args) { // 请求接口 String result = HttpRequest.get("http://localhost:8000/tmerclub_user/user/userInfo") .header("Content-Type","application/json") // 设置请求头,传已经同步到系统的token .header("Authorization", "token_test") .execute().body(); // +++++++++++++++++++++++++++++++++ 获取响应数据+++++++++++++++++++++++++++++++++ // 响应数据 TreeMap responseMap = JSONObject.parseObject(result, TreeMap.class); System.out.println(responseMap.get("data")); } ``` 输出结果 ![img.png](../img/基本开发文档/第三方接口对接协议/请求获取用户详情输出结果.png)