访问令牌(Access Token)是调用智能语音服务的凭证。我们提供了基于阿里云公共SDK调用云端服务获取Access Token的方式。如果您希望自己实现获取Access Token的客户端程序,请阅读下面的获取Access Token的接口协议说明。
请求报文实例
客户端向服务端发送获取Token的请求,服务端返回创建Token结果的响应。客户端发送的请求支持使用HTTP或者HTTPS协议,请求方法支持GET或者POST方法。服务端提供了基于阿里云POP协议的接口,因此客户端需要实现阿里云POP的签名机制。
由于HTTPS协议的请求参数设置与HTTP协议相同,下面将以HTTP协议请求为例,介绍如何发送获取Token请求。
URL
协议 | URL | 方法 |
---|---|---|
HTTP/1.1 | http://nlsmeta.ap-southeast-1.aliyuncs.com/ | GET 或 POST |
请求参数
说明:
- 使用GET方法,需要将请求参数设置到请求行中:
/?请求参数字符串
; - 使用POST方法,需要将请求参数设置到请求的Body中。
名称 | 类型 | 是否必需 | 说明 |
---|---|---|---|
AccessKeyId | String | 是 | 阿里云颁发给您的访问服务所用的密钥ID,请填入您的阿里云账号的AccessKey ID |
Action | String | 是 | POP API名称:CreateToken |
Version | String | 是 | POP API版本:2019-07-17 |
Format | String | 是 | 响应返回的类型:JSON |
RegionId | String | 是 | 服务所在的地域ID:ap-southeast-1 |
Timestamp | String | 是 | 请求的时间戳。日期格式按照ISO 8601标准表示,并需要使用UTC时间,时区为:+0(请勿使用本地时间,如北京时间)。格式为YYYY-MM-DDThh:mm:ssZ。例如2019-04-03T06:15:03Z 为UTC时间2019年4月3日6点15分03秒。 |
SignatureMethod | String | 是 | 签名算法:HMAC-SHA1 |
SignatureVersion | String | 是 | 签名算法版本:1.0 |
SignatureNonce | String | 是 | 唯一随机数uuid,用于请求的防重放攻击,每次请求唯一,不能重复使用。格式为xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx(8-4-4-4-12),例如8d1e6a7a-f44e-40d5-aedb-fe4a1c80f434 |
Signature | String | 是 | 由所有请求参数计算出的签名结果,生成方法请参考下文签名机制。 |
HTTP请求头部
HTTP 请求头部由“关键字/值”对组成,每行一对,关键字和值用英文冒号“:”分隔,设置内容为如下表格:
名称 | 类型 | 是否必需 | 描述 |
---|---|---|---|
Host | String | 否 | HTTP请求的服务器域名:nlsmeta.ap-southeast-1.aliyuncs.com,一般会根据请求链接自动解析 |
Accept | String | 否 | 指定客户端能够接收的内容类型:application/json,不设置默认为 */* |
Content-type | String | POST方法必须设置 | 指定POST方法请求的Body数据格式:application/x-www-form-urlencoded |
报文示例
HTTP GET请求报文:
GET /?Signature=O0s6pfeOxtFM6YKSZKQdSyPR9Vs%3D&AccessKeyId=LTA******F3s&Action=CreateToken&Format=JSON&RegionId=ap-southeast-1&SignatureMethod=HMAC-SHA1&SignatureNonce=a1f01895-6ff1-43c1-ba15-6c109fa00106&SignatureVersion=1.0&Timestamp=2019-03-27T09%3A51%3A25Z&Version=2019-07-17 HTTP/1.1
Host: nlsmeta.ap-southeast-1.aliyuncs.com
User-Agent: curl/7.49.1
Accept: */*
HTTP POST请求报文:
POST / HTTP/1.1
Host: nlsmeta.ap-southeast-1.aliyuncs.com
User-Agent: curl/7.49.1
Accept: */*
Content-type: application/x-www-form-urlencoded
Content-Length: 276
SignatureVersion=1.0&Action=CreateToken&Format=JSON&SignatureNonce=8d1e6a7a-f44e-40d5-aedb-fe4a1c80f434&Version=2019-07-17&AccessKeyId=LTA******F3s&Signature=oT8A8RgvFE1tMD%2B3hDbGuoMQSi8%3D&SignatureMethod=HMAC-SHA1&RegionId=ap-southeast-1&Timestamp=2019-03-25T09%3A07%3A52Z
响应结果
发送获取Token的HTTP请求之后,会收到服务端的响应,结果以JSON字符串的形式保存在该响应中。GET方法和POST方法的响应结果相同。
- 成功响应HTTP状态码为200,响应字段说明:
参数 | 类型 | 说明 |
---|---|---|
Token | token对象 | 包含了具体的token值和有效期时间戳 |
Id | String | 本次请求分配的token值 |
ExpireTime | Long | token的有效期时间戳(单位:秒,例如1553825814换算为北京时间为:2019/3/29 10:16:54,即token在该时间之前有效。) |
HTTP/1.1 200 OK
Date: Mon, 25 Mar 2019 09:29:24 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 216
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, X-Sequence, _aop_secret, _aop_signature
Access-Control-Max-Age: 172800
Server: Jetty(7.2.2.v20101205)
{"NlsRequestId":"dd05a301b40441c99a2671905325fb1f","RequestId":"E11F2DC2-0163-4D97-A704-0BD28045608A","ErrMsg":"","Token":{"ExpireTime":1553592564,"Id":"889******166","UserId":"150**********151"}}
响应Body JSON字符串格式解析:
{
"NlsRequestId": "dd05a301b40441c99a2671905325fb1f",
"RequestId": "E11F2DC2-0163-4D97-A704-0BD28045608A",
"ErrMsg": "",
"Token": {
"ExpireTime": 1553592564,
"Id": "889******166",
"UserId": "150**********151"
}
}
- 失败响应HTTP状态码为非200,响应字段说明:
参数 | 类型 | 说明 |
---|---|---|
RequestId | String | 请求ID |
Message | String | 失败响应的错误信息 |
Code | String | 失败响应的错误码 |
说明: 请根据错误码和错误信息提示检查请求参数是否设置正确,如不能排查,请将响应信息提交到工单。
以重传入阿里云账号的AccessKey Id错误为例:
HTTP/1.1 404 Not Found
Date: Thu, 28 Mar 2019 07:23:01 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 290
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, X-Sequence, _aop_secret, _aop_signature
Access-Control-Max-Age: 172800
Server: Jetty(7.2.2.v20101205)
{"Recommend":"https://error-center.aliyun.com/status/search?Keyword=InvalidAccessKeyId.NotFound&source=PopGw","Message":"Specified access key is not found.","RequestId":"A51587CB-5193-4DB8-9AED-CD4365C2D1E1","HostId":"nlsmeta.ap-southeast-1.aliyuncs.com","Code":"InvalidAccessKeyId.NotFound"}
响应Body JSON字符串格式解析:
{
"Recommend": "https://error-center.aliyun.com/status/search?Keyword=InvalidAccessKeyId.NotFound&source=PopGw",
"Message": "Specified access key is not found.",
"RequestId": "A51587CB-5193-4DB8-9AED-CD4365C2D1E1",
"HostId": "nlsmeta.ap-southeast-1.aliyuncs.com",
"Code": "InvalidAccessKeyId.NotFound"
}
签名机制
服务端POP API对每个接口访问请求的发送者都要进行身份验证,所以无论使用HTTP协议还是HTTPS协议提交的请求,都需要在请求中包含签名信息。通过签名机制,服务端可以确认哪位客户在做API请求,并能确认客户请求在网络传输过程中有无被篡改。
安全验证流程
计算签名时,需要您的阿里云账号的AccessKeyId 和 AccessKeySecret,使用HMAC-SHA1算法进行对称加密。其工作流程如下:
- 请求端根据API请求内容(包括HTTP 请求参数和Body)生成签名字符串。
- 请求端使用阿里云账号的AccessKeyId 和 AccessKeySecret对第一步生成的签名字符串进行签名,获得该API请求的数字签名。
- 请求端把API请求内容和数字签名一同发送给服务端。
- 服务端在接收到请求后会重复如上的第1、2步工作(服务端会在后台获取该请求使用的用户秘钥)并在服务端计算出该请求期望的数字签名。
- 服务端用期望的数字签名和请求端发送过来的数字签名做对比,如果完全一致则认为该请求通过验证。否则直接拒绝该请求。
生成请求的签名字符串
1. 构造规范化的请求字符串
将HTTP的请求参数(不包括Signature)构造成规范化的请求字符串。规范化步骤:
- 参数排序。按参数名的字典顺序,对请求参数进行排序,严格按照大小写敏感排序。
- 编码参数,对排序后的请求参数进行规范化设置。 请求参数的名称和值都要使用UTF-8字符集进行URL编码,URL编码规则如下:
- 对于字符 A-Z、a-z、0-9以及字符
-
、_
、.
、~
不编码; - 对于其他字符编码成“%XY”的格式,其中XY是字符对应ASCII码的16进制表示。比如英文的双引号(”)对应的编码就是%22;
- 对于扩展的UTF-8字符,编码成“%XY%ZA…”的格式;
- 需要说明的是英文空格要被编码是%20,而不是加号
+
;注:一般支持URL编码的库(比如Java中的java.net.URLEncoder)都是按照“application/x-www-form-urlencoded”的MIME类型的规则进行编码的。实现时可以直接使用此类方式进行编码,然后把编码后的字符串中:加号+
替换为%20
,星号*
替换为%2A
,%7E
替换为波浪号~
,即可得到上述规则描述的编码字符串。
- 对于字符 A-Z、a-z、0-9以及字符
- 使用等号
=
连接URL编码后的参数名和参数值:percentEncode(参数Key) + “=” + percentEncode(参数值)
。 - 使用与号
&
连接第4步URL编码后的请求参数对,例如Action=CreateToken&Format=JSON
。 - 返回规范化的请求字符串(注意:字符串中第一个参数名前面不需要
&
符号)。
构造规范化的请求字符串代码示例:
String percentEncode(String value) throws UnsupportedEncodingException {
return value != null ? URLEncoder.encode(value, URL_ENCODING)
.replace("+", "%20")
.replace("*", "%2A")
.replace("%7E", "~") : null;
}
// 对参数Key排序
String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {});
Arrays.sort(sortedKeys);
// 对排序的参数进行编码、拼接
for (String key : sortedKeys) {
canonicalizedQueryString.append("&")
.append(percentEncode(key)).append("=")
.append(percentEncode(queryParamsMap.get(key)));
}
queryString = canonicalizedQueryString.toString().substring(1);
完整代码实现请阅读完整示例的canonicalizedQuery
函数。
构造规范化的请求字符串:
AccessKeyId=LTA******3s2&Action=CreateToken&Format=JSON&RegionId=ap-southeast-1&SignatureMethod=HMAC-SHA1&SignatureNonce=f20b1beb-e5dc-4245-9e96-aa582e905c1a&SignatureVersion=1.0&Timestamp=2019-04-03T03%3A40%3A13Z&Version=2019-07-17
2. 构造待签名字符串
将HTTP请求的方法(GET)、URL编码的URL路径(/)、URL编码的第1步获取的规范化的请求字符串使用与符号&
连接成待签名字符串:
HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(queryString)
构造签名字符串代码示例:
StringBuilder strBuilderSign = new StringBuilder();
strBuilderSign.append(HTTPMethod);
strBuilderSign.append("&");
strBuilderSign.append(percentEncode(urlPath));
strBuilderSign.append("&");
strBuilderSign.append(percentEncode(queryString));
stringToSign = strBuilderSign.toString();
完整代码实现请阅读完整示例的createStringToSign
函数。
构造的签名字符串:
3. 计算签名
- 签名采用HMAC-SHA1算法 + Base64,编码采用UTF-8。
- 根据您的AccessKeySecret,将第2步构造的待签名字符串使用HMAC-SHA1算法计算出对应的数字签名。其中,计算签名时使用的AccessKeySecret必须在其后面增加一个与字符
&
。 - 签名也要做URL编码。
计算签名的代码示例:
signature = Base64( HMAC-SHA1(stringToSign, accessKeySecret + "&") );
// 进行URL编码
signature = percentEncode(signature)
完整代码实现请阅读完整示例的sign
函数。
计算得到的签名:
# 签名串
AKIktdPUMCV12fTh667BLXeuCtg=
# URL编码后的结果
AKIktdPUMCV12fTh667BLXeuCtg%3D
计算签名后,将签名的键值对用符号=
连接,并使用符号&
添加到第1步获取的请求字符串中,作为HTTP GET请求参数,发送到服务端,获取token。
String queryStringWithSign = "Signature=" + signature + "&" + queryString;
快速测试
您可以使用以下参数,计算签名,比较计算结果是否一致。
说明:AccessKeyId和AccessKeySecret没有提供真实数据,Timestamp是过期的时间,使用这些参数计算的签名,获取Token时会失败,仅用于计算签名测试对比。
- AccessKeyId:
my_access_key_id
- AccessKeySecret:
my_access_key_secret
- Timestamp:
2019-04-18T08:32:31Z
- SignatureNonce:
b924c8c3-6d03-4c5d-ad36-d984d3116788
请求参数如下
AccessKeyId:my_access_key_id
Action:CreateToken
Version:2019-07-17
Timestamp:2019-04-18T08:32:31Z
Format:JSON
RegionId:ap-southeast-1
SignatureMethod:HMAC-SHA1
SignatureVersion:1.0
SignatureNonce:b924c8c3-6d03-4c5d-ad36-d984d3116788
1.规范化后的请求字符串:
AccessKeyId=my_access_key_id&Action=CreateToken&Format=JSON&RegionId=ap-southeast-1&SignatureMethod=HMAC-SHA1&SignatureNonce=b924c8c3-6d03-4c5d-ad36-d984d3116788&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Version=2019-07-17
2.构造的待签名字符串:
格式如下:
HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(queryString)
3.计算得到的签名:
hHq4yNsPitlfDJ2L0nQPdugdEzM=
# URL 编码后的结果
hHq4yNsPitlfDJ2L0nQPdugdEzM%3D
4.带有签名的请求字符串:
Signature=hHq4yNsPitlfDJ2L0nQPdugdEzM%3D&AccessKeyId=my_access_key_id&Action=CreateToken&Format=JSON&RegionId=ap-southeast-1&SignatureMethod=HMAC-SHA1&SignatureNonce=b924c8c3-6d03-4c5d-ad36-d984d3116788&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Version=2019-07-17
5.组合成的HTTP请求链接:
http://nlsmeta.ap-southeast-1.aliyuncs.com/?Signature=hHq4yNsPitlfDJ2L0nQPdugdEzM%3D&AccessKeyId=my_access_key_id&Action=CreateToken&Format=JSON&RegionId=ap-southeast-1&SignatureMethod=HMAC-SHA1&SignatureNonce=b924c8c3-6d03-4c5d-ad36-d984d3116788&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Version=2019-07-17
6.替换第5步获取的HTTP请求链接,使用浏览器或者curl,获取Token:
curl "http://nlsmeta.ap-southeast-1.aliyuncs.com/?Signature=${您的签名}&AccessKeyId=${您的AccessKey Id}&Action=CreateToken&Format=JSON&RegionId=ap-southeast-1&SignatureMethod=HMAC-SHA1&SignatureNonce=${您的请求UUID}&SignatureVersion=1.0&Timestamp=${您的请求时间戳}&Version=2019-07-17"
完整示例
说明: 文档提供了Java、Python语言示例代码,您可根据协议和示例实现其他语言的客户端程序。
Java Demo
依赖:
<!-- http://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.1</version>
</dependency>
Demo程序:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.UUID;
public class CreateToken {
private final static String TIME_ZONE = "GMT";
private final static String FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private final static String URL_ENCODING = "UTF-8";
private static final String ALGORITHM_NAME = "HmacSHA1";
private static final String ENCODING = "UTF-8";
private static String token = null;
private static long expireTime = 0;
/**
* 获取时间戳
* 必须符合ISO8601规范,并需要使用UTC时间,时区为+0
*/
public static String getISO8601Time(Date date) {
Date nowDate = date;
if (null == date) {
nowDate = new Date();
}
SimpleDateFormat df = new SimpleDateFormat(FORMAT_ISO8601);
df.setTimeZone(new SimpleTimeZone(0, TIME_ZONE));
return df.format(nowDate);
}
/**
* 获取UUID
*/
public static String getUniqueNonce() {
UUID uuid = UUID.randomUUID();
return uuid.toString();
}
/**
* URL编码
* 使用UTF-8字符集按照 RFC3986 规则编码请求参数和参数取值
*/
public static String percentEncode(String value) throws UnsupportedEncodingException {
return value != null ? URLEncoder.encode(value, URL_ENCODING).replace("+", "%20")
.replace("*", "%2A").replace("%7E", "~") : null;
}
/***
* 将参数排序后,进行规范化设置,组合成请求字符串
* @param queryParamsMap 所有请求参数
* @return 规范化的请求字符串
*/
public static String canonicalizedQuery( Map<String, String> queryParamsMap) {
String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {});
Arrays.sort(sortedKeys);
String queryString = null;
try {
StringBuilder canonicalizedQueryString = new StringBuilder();
for (String key : sortedKeys) {
canonicalizedQueryString.append("&")
.append(percentEncode(key)).append("=")
.append(percentEncode(queryParamsMap.get(key)));
}
queryString = canonicalizedQueryString.toString().substring(1);
System.out.println("规范化后的请求参数串:" + queryString);
} catch (UnsupportedEncodingException e) {
System.out.println("UTF-8 encoding is not supported.");
e.printStackTrace();
}
return queryString;
}
/***
* 构造签名字符串
* @param method HTTP请求的方法
* @param urlPath HTTP请求的资源路径
* @param queryString 规范化的请求字符串
* @return 签名字符串
*/
public static String createStringToSign(String method, String urlPath, String queryString) {
String stringToSign = null;
try {
StringBuilder strBuilderSign = new StringBuilder();
strBuilderSign.append(method);
strBuilderSign.append("&");
strBuilderSign.append(percentEncode(urlPath));
strBuilderSign.append("&");
strBuilderSign.append(percentEncode(queryString));
stringToSign = strBuilderSign.toString();
System.out.println("构造的签名字符串:" + stringToSign);
} catch (UnsupportedEncodingException e) {
System.out.println("UTF-8 encoding is not supported.");
e.printStackTrace();
}
return stringToSign;
}
/***
* 计算签名
* @param stringToSign 签名字符串
* @param accessKeySecret 阿里云AccessKey Secret加上与号&
* @return 计算得到的签名
*/
public static String sign(String stringToSign, String accessKeySecret) {
try {
Mac mac = Mac.getInstance(ALGORITHM_NAME);
mac.init(new SecretKeySpec(
accessKeySecret.getBytes(ENCODING),
ALGORITHM_NAME
));
byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING));
String signBase64 = DatatypeConverter.printBase64Binary(signData);
System.out.println("计算的得到的签名:" + signBase64);
String signUrlEncode = percentEncode(signBase64);
System.out.println("UrlEncode编码后的签名:" + signUrlEncode);
return signUrlEncode;
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e.toString());
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException(e.toString());
} catch (InvalidKeyException e) {
throw new IllegalArgumentException(e.toString());
}
}
/***
* 发送HTTP GET请求,获取token和有效期时间戳
* @param queryString 请求参数
*/
public static void processGETRequest(String queryString) {
/**
* 设置HTTP GET请求
* 1. 使用HTTP协议
* 2. Token服务域名:nlsmeta.ap-southeast-1.aliyuncs.com
* 3. 请求路径:/
* 4. 设置请求参数
*/
String url = "http://nlsmeta.ap-southeast-1.aliyuncs.com";
url = url + "/";
url = url + "?" + queryString;
System.out.println("HTTP请求链接:" + url);
Request request = new Request.Builder()
.url(url)
.header("Accept", "application/json")
.get()
.build();
try {
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
String result = response.body().string();
if (response.isSuccessful()) {
JSONObject rootObj = JSON.parseObject(result);
JSONObject tokenObj = rootObj.getJSONObject("Token");
if (tokenObj != null) {
token = tokenObj.getString("Id");
expireTime = tokenObj.getLongValue("ExpireTime");
}
else{
System.err.println("提交获取Token请求失败: " + result);
}
}
else {
System.err.println("提交获取Token请求失败: " + result);
}
response.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
if (args.length < 2) {
System.err.println("CreateTokenDemo need params: <AccessKey Id> <AccessKey Secret>");
System.exit(-1);
}
String accessKeyId = args[0];
String accessKeySecret = args[1];
System.out.println(getISO8601Time(null));
// 所有请求参数
Map<String, String> queryParamsMap = new HashMap<String, String>();
queryParamsMap.put("AccessKeyId", accessKeyId);
queryParamsMap.put("Action", "CreateToken");
queryParamsMap.put("Version", "2019-07-17");
queryParamsMap.put("Timestamp", getISO8601Time(null));
queryParamsMap.put("Format", "JSON");
queryParamsMap.put("RegionId", "ap-southeast-1");
queryParamsMap.put("SignatureMethod", "HMAC-SHA1");
queryParamsMap.put("SignatureVersion", "1.0");
queryParamsMap.put("SignatureNonce", getUniqueNonce());
/**
* 1.构造规范化的请求字符串
*/
String queryString = canonicalizedQuery(queryParamsMap);
if (null == queryString) {
System.out.println("构造规范化的请求字符串失败!");
return;
}
/**
* 2.构造签名字符串
*/
String method = "GET"; // 发送请求的 HTTP 方法,GET
String urlPath = "/"; // 请求路径
String stringToSign = createStringToSign(method, urlPath, queryString);
if (null == stringToSign) {
System.out.println("构造签名字符串失败");
return;
}
/**
* 3.计算签名
*/
String signature = sign(stringToSign, accessKeySecret + "&");
if (null == signature) {
System.out.println("计算签名失败!");
return;
}
/**
* 4.将签名加入到第1步获取的请求字符串
*/
String queryStringWithSign = "Signature=" + signature + "&" + queryString;
System.out.println("带有签名的请求字符串:" + queryStringWithSign);
/**
* 5.发送HTTP GET请求,获取token
*/
processGETRequest(queryStringWithSign);
if (token != null) {
System.out.println("获取的Token:" + token + ", 有效期时间戳(秒):" + expireTime);
// 将10位数的时间戳转换为北京时间
String expireDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(expireTime * 1000));
System.out.println("Token有效期的北京时间:" + expireDate);
}
}
}
Python Demo
说明:
- Python版本要求:Python3.4及以上。
- 请安装Python HTTP库Requests:
pip install requests
Demo程序:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import base64
import hashlib
import hmac
import requests
import time
import uuid
from urllib import parse
class AccessToken:
@staticmethod
def _encode_text(text):
encoded_text = parse.quote_plus(text)
return encoded_text.replace('+', '%20').replace('*', '%2A').replace('%7E', '~')
@staticmethod
def _encode_dict(dic):
keys = dic.keys()
dic_sorted = [(key, dic[key]) for key in sorted(keys)]
encoded_text = parse.urlencode(dic_sorted)
return encoded_text.replace('+', '%20').replace('*', '%2A').replace('%7E', '~')
@staticmethod
def create_token(access_key_id, access_key_secret):
parameters = {'AccessKeyId': access_key_id,
'Action': 'CreateToken',
'Format': 'JSON',
'RegionId': 'ap-southeast-1',
'SignatureMethod': 'HMAC-SHA1',
'SignatureNonce': str(uuid.uuid1()),
'SignatureVersion': '1.0',
'Timestamp': time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
'Version': '2019-07-17'}
# 构造规范化的请求字符串
query_string = AccessToken._encode_dict(parameters)
print('规范化的请求字符串: %s' % query_string)
# 构造待签名字符串
string_to_sign = 'GET' + '&' + AccessToken._encode_text('/') + '&' + AccessToken._encode_text(query_string)
print('待签名的字符串: %s' % string_to_sign)
# 计算签名
secreted_string = hmac.new(bytes(access_key_secret + '&', encoding='utf-8'),
bytes(string_to_sign, encoding='utf-8'),
hashlib.sha1).digest()
signature = base64.b64encode(secreted_string)
print('签名: %s' % signature)
# 进行URL编码
signature = AccessToken._encode_text(signature)
print('URL编码后的签名: %s' % signature)
# 调用服务
full_url = 'http://nlsmeta.ap-southeast-1.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
print('url: %s' % full_url)
# 提交HTTP GET请求
response = requests.get(full_url)
if response.ok:
root_obj = response.json()
key = 'Token'
if key in root_obj:
token = root_obj[key]['Id']
expire_time = root_obj[key]['ExpireTime']
return token, expire_time
print(response.text)
return None, None
if __name__ == "__main__":
# 用户信息
access_key_id = '您的AccessKeyId'
access_key_secret = '您的AccessKeySecret'
token, expire_time = AccessToken.create_token(access_key_id, access_key_secret)
print('token: %s, expire time(s): %s' % (token, expire_time))
if expire_time:
print('token有效期的北京时间:%s' % (time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expire_time))))