认证与调用
API平台同时可支持基于固定API-TOKEN认证、动态AK-SK、USER-TOKEN三种认证方式,三种方式的差异:
- 固定的API-TOKEN:每个用户申请每个API,均会生成一个唯一的API-TOKEN(即3个用户申请了同一个API,每个用户都有自己的TOKEN)。API-TOKEN放在Header中传入,优点是调用比较简单,缺点是API-TOKEN泄露后可能产生数据被误调用。
- 动态AK-SK:根据每次请求的内容动态生成签名(Signature),安全性高,但需要调用方来动态生成前面,有少量开发工作量。
- USER-TOKEN:每个用户有自己唯一的TOKEN,用户申请了多个API,可统一使用自己的USER-TOKEN来调用不同的API,避免了产生/管理大量API-TOKEN的问题。若使用USER-TOKEN,需要管理员提前对相关的API开启USER-TOKEN模式。
- API-TOKEN、动态AK/SK支持调用测试,USER-TOKEN不支持调用测试。
API-TOKEN
用户申请API,并审批通过之后,可在「API管理-我的API-API申请」页面中查看,点击某个API,可查看详细信息:
调用参数如下:
调用的URL
Header
- API-TOKEN
- Content-Type : application/json
入参(Body)
将上述信息拷贝至Postman,如下图所示:
API-TOKEN
作为Header参数传入,key值不区分大小写,可填写API-TOKEN
或api-token
Content-Type
设置为application/json
,不支持以其他格式传入。Body的输入模式选择为
raw
,格式为JSON
,不支持其他格式传入。在Body中的入参:
{
"inFields": {
"id":"i001"
}
}
利用Postman发送请求,即可查看返回的数据,详细的返回信息说明可参考API创建
AK/SK认证
AK/SK签名原理
- 客户端:
- 构建请求(包含 Access Key)。
- 使用请求内容和使用Secret Access Key计算的签名(Signature)。
- 发送请求(包含Access Key,Signature)到服务端。
- 服务端:
- 根据发送的Access Key查找数据库得到对应的Secret-Key。
- 使用同样的算法将请求内容和Secret-Key一起计算签名(Signature)。
- 对比用户发送的签名和服务端计算的签名,两者相同则认证通过,否则失败。
生成签名代码
- 具体流程
准备参与签名的字段,需要注意参与签名的字段信息与完整的入参有差异,只需入参中inFields的value部分即可:
//完整的入参信息包含「inFields」字段
{
"pageNo": 1,
"pageSize": 10,
"inFields": {
"id": "i001"
}
}
//但是参与签名的字段,只需传入inFields的value部分即可,分页信息不参与签名生成:
{
"id": "i001"
}
将签名字段的KeyValuePair按照Key的字典顺序排列(AaBb-Zz,0-9顺序,即大写字母排在小写字母前,数字排在字母后),然后组装成
Key1=Value1&Key2=Value2…&Key n=Value n & APP Secret
的字符串(需注意APP Secret
放在最后)。对生成的字符串进行128位md5算法做信息摘要,并转小写。
第3步得到的32位长度的全小写字符串即为生成的签名。
- 排序示例
- 参与签名的字段:
X-Auth-Key = value1;X-Auth-ActionId = value2;X-Auth-Timestamp = value3;prod = value4
- 排序结果:
X-Auth-ActionId=value2X-Auth-Key=value1X-Auth-Timestamp=value3prod=value4APP Secret=value5
- 参与签名的字段:
- 生成示例 以下是一段 JAVA 代码生成签名的示例,以供用户参考。
package com.host.da;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* @author author_name
* @date 2022-07-13
*/
public class KeyTest {
public static void main(String[] args) throws Exception {
Map<String, Object> param = new HashMap<>();
String sign = getSign("53971d34910f4f89b7f4cb6967bd96cd", param);
System.out.println("md5信息摘要后: " + sign);
}
public static String getSign(String appSecret, Map<String, Object> param) throws Exception {
String formattedString = formatSignatureParam(appSecret, param);
System.out.println("原始参数md5前: " + formattedString);
return Hashing.md5().hashBytes(formattedString.getBytes(Charsets.UTF_8)).toString();
}
/**
* @param sk app secret
* @param param 参数map,包括header,query和body中的参数
* @return
*/
private static String formatSignatureParam(String sk, Map<String, Object> param) {
if (param == null) {
throw new RuntimeException("error param");
}
//申请api时的apiId
param.put("X-Auth-ActionId", 100565);
//app key
param.put("X-Auth-Key", 3);
//当前时间戳,如果时间与服务端时间相差大于10分钟,此次请求将判定为签名错误
param.put("X-Auth-Timestamp", System.currentTimeMillis());
//todo:post请求加上body内参数,get请求加上form表单内参数
//需根据自身API的入参替换这部分内容
param.put("voltage","100");
System.out.println("时间戳:" + System.currentTimeMillis());
//使用TreeMap可以自动按照key字典顺序排序
TreeMap<String, String> paramMap = new TreeMap<>();
for (Map.Entry<String, Object> en : param.entrySet()) {
if (null == en.getValue()) {
continue;
}
//参数应当均为基本类型
paramMap.put(en.getKey(), en.getValue().toString());
}
Set<Map.Entry<String, String>> entries = paramMap.entrySet();
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String val = entry.getValue();
builder.append(key)
.append("=")
.append(val)
.append("&");
}
return builder.append(sk).toString();
}
}
调用传参
AK/SK方式的部分参数与API-TOKEN略有不同,主要差异在Header中的参数,说明如下:
- 调用的URL:与API-TOKEN相同
- Header:
- X-Auth-Key: {APP Key},进入「API管理-我的API-API调用」页面,可查看
APP Key
的值。 - X-Auth-ActionId: {API Id},进入「API管理-我的API-API申请」页面,可在API详情中查看
API ID
的值。 - X-Auth-Signature: {生成的签名},根据上文的代码生成的签名的值。
- X-Auth-Timestamp: {时间戳},调用的时间戳,此时间戳也会参与签名的生成。
- Content-Type : application/json
- X-Auth-Key: {APP Key},进入「API管理-我的API-API调用」页面,可查看
- 入参(Body):与API-TOKEN相同
每个用户在每个租户内有唯一的APP Key,同一个用户在不同租户的Key值不同。
USER-TOKEN认证
每个用户有唯一的USER-TOKEN,可使用一个USER-TOKEN调用不同的API,无需为每个API单独维护API-TOKEN的问题。使用USER-TOKEN的前提:
- 用户经申请/审批后,有权限调用此API
- 此API开启了USER-TOKEN认证模式,开启方式见API安全策略与限制
点击「API管理-我的API-API调用」页面可以获取当前用户的USER-TOKEN,也可以在页面进行「重置」操作,注意:重置将立即生效,可能会影响正常的API调用。
使用USER-TOKEN调用API时的Header参数与其他方式不同,需传入如下参数:
- 调用的URL
- Header:
- USER-TOKEN:进入「API管理-我的API-API调用」页面查看。USER-TOKEN的key值不区分大小写。
- apiId:进入「API管理-我的API-API申请」页面,可在API详情中查看
API ID
的值。 - Content-Type : application/json。
- 入参(Body):与API-TOKEN相同。
使用Postman模拟调用如下图所示:
调用测试
在正式申请调用API之前,管理员可先行测试,查看调用方式、入参、返回参数是否有误。
进入「API管理-API管理-API」菜单,将待测试的API点击「提交」,即可对此API做调用测试。在「API管理-API管理-API」页面,获取测试API的所需信息。
API-TOKEN、动态AK/SK支持调用测试,USER-TOKEN不支持调用测试。
API-TOKEN测试
- 调用的URL
- 用于测试的API-TOKEN
- 入参(Body)
将上述信息拷贝至Postman,如下图所示:
API-TOKEN
作为Header参数传入,可填写API-TOKEN
或api-token
Content-Type
设置为application/json
,不支持以其他格式传入。Body的输入模式选择为
raw
,格式为JSON
,不支持其他格式传入。在Body中的入参:
{
"inFields": {
"id":"i001"
}
}
利用Postman发送请求进行测试。
AK/SK测试
生成签名
测试阶段,可利用此网址生成签名:https://codepen.io/hsunboy/pen/RdYyRb。如下图所示,注意:
- Body中不是全部的入参,而是
inFields
中的value部分,参考生成签名代码。 - header、query中不需要输入。
在Postman中输入对应的信息,如下图所示:
只有API管理员及以上角色才有权限进行API测试
curl命令调用测试
几种不同认证方式下的curl命令样例如下:
API-TOKEN
curl -i -X POST \
-H "Content-Type:application/json" \
-H "API-TOKEN:8C2EFA40CF5A09AAB1ED067196714408276B794EE238919E35C135526CEECAA7" \
-d \
'{
"pageNo": 1,
"pageSize": 10,
"inFields": {
"user_id": 1
}
}' \
'http://host:port/api/gateway/wizard_user_info'
注意上述样例中的 API-TOKEN
、body
参数、调用URL根据实际情况进行替换。