通過OpenAPI獲取Token
通過OpenAPI獲取Token的方式,要求開發(fā)者自行編寫代碼完成身份驗(yàn)證和請求邏輯,如果對應(yīng)的編程語言缺少SDK,或者需要控制依賴組件,可以通過OpenAPI獲取Token。本文介紹如何通過OpenAPI獲取Token。
請求報(bào)文
客戶端向服務(wù)端發(fā)送獲取Token的請求,服務(wù)端返回創(chuàng)建Token結(jié)果的響應(yīng)。客戶端發(fā)送的請求支持使用HTTP/HTTPS協(xié)議,請求方法支持GET/POST方法。服務(wù)端提供了基于阿里云POP協(xié)議的接口,因此客戶端需要實(shí)現(xiàn)阿里云POP的簽名機(jī)制。
由于HTTPS協(xié)議的請求參數(shù)設(shè)置與HTTP協(xié)議相同,下面以HTTP協(xié)議請求為例,介紹如何發(fā)送請求獲取Token。
URL
協(xié)議
URL
方法
HTTP/1.1
http://nls-meta.cn-shanghai.aliyuncs.com/
GET/POST
請求參數(shù)
名稱
類型
是否必選
說明
AccessKeyId
String
是
阿里云賬號(hào)AccessKey ID
Action
String
是
POP API名稱:CreateToken
Version
String
是
POP API版本:2019-02-28
Format
String
是
響應(yīng)返回的類型:JSON
RegionId
String
是
服務(wù)所在的地域ID:cn-shanghai
Timestamp
String
是
請求的時(shí)間戳。日期格式按照ISO 8601標(biāo)準(zhǔn)表示,且使用UTC時(shí)間,時(shí)區(qū):+0。格式:YYYY-MM-DDThh:mm:ssZ。如2019-04-03T06:15:03Z為UTC時(shí)間2019年4月3日6點(diǎn)15分03秒。
SignatureMethod
String
是
簽名算法:HMAC-SHA1
SignatureVersion
String
是
簽名算法版本:1.0
SignatureNonce
String
是
唯一隨機(jī)數(shù)uuid,用于請求的防重放攻擊,每次請求唯一,不能重復(fù)使用。格式為A-B-C-D-E(A、B、C、D、E的字符位數(shù)分別為8、4、4、4、12)。例如,8d1e6a7a-f44e-40d5-aedb-fe4a1c80f434。
Signature
String
是
由所有請求參數(shù)計(jì)算出的簽名結(jié)果,生成方法參見下文簽名機(jī)制。
說明使用GET方法,需要將請求參數(shù)設(shè)置在請求行中:
/?請求參數(shù)字符串
。使用POST方法,需要將請求參數(shù)設(shè)置在請求體中。
HTTP請求頭部
HTTP請求頭部由“關(guān)鍵字-值”對組成,每行一對,關(guān)鍵字和值用英文冒號(hào)“:”分隔,內(nèi)容如下:
名稱
類型
是否必選
描述
Host
String
否
HTTP請求的服務(wù)器域名:
nls-meta.cn-shanghai.aliyuncs.com
,一般根據(jù)請求鏈接自動(dòng)解析。Accept
String
否
指定客戶端能夠接收的內(nèi)容類型:
application/json
,不設(shè)置默認(rèn)為 */* 。Content-type
String
POST方法必須設(shè)置
指定POST方法請求體數(shù)據(jù)格式:
application/x-www-form-urlencoded
。
報(bào)文示例:
HTTP GET請求報(bào)文
GET /?Signature=O0s6pfeOxtFM6YKSZKQdSyPR9Vs%3D&AccessKeyId=LTAF3sAA****&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=a1f01895-6ff1-43c1-ba15-6c109fa00106&SignatureVersion=1.0&Timestamp=2019-03-27T09%3A51%3A25Z&Version=2019-02-28 HTTP/1.1 Host: nls-meta.cn-shanghai.aliyuncs.com User-Agent: curl/7.49.1 Accept: */*
HTTP POST請求報(bào)文
POST / HTTP/1.1 Host: nls-meta.cn-shanghai.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-02-28&AccessKeyId=LTAF3sAA****&Signature=oT8A8RgvFE1tMD%2B3hDbGuoMQSi8%3D&SignatureMethod=HMAC-SHA1&RegionId=cn-shanghai&Timestamp=2019-03-25T09%3A07%3A52Z
響應(yīng)結(jié)果:
發(fā)送獲取Token的HTTP請求后,會(huì)受到服務(wù)端響應(yīng),結(jié)果以JSON字符串的形式保存在響應(yīng)中,GET方法和POST方法的響應(yīng)結(jié)果相同。
成功響應(yīng)
HTTP狀態(tài)碼為200,響應(yīng)字段如下表所示。
參數(shù)
類型
說明
Token
Token對象
包含Token值和有效期時(shí)間戳。
Id
String
請求分配的Token值。
ExpireTime
Long
Token的有效期時(shí)間戳(單位:秒。例如1553825814換算為北京時(shí)間為:2019/3/29 10:16:54,即Token在該時(shí)間之前有效。)。
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":"dd05a301b40441c99a2671905325****","RequestId":"E11F2DC2-0163-4D97-A704-0BD28045****","ErrMsg":"","Token":{"ExpireTime":1553592564,"Id":"88916699****","UserId":"150151111111****"}}
響應(yīng)體JSON字符串內(nèi)容如下。
{ "NlsRequestId": "dd05a301b40441c99a2671905325****", "RequestId": "E11F2DC2-0163-4D97-A704-0BD28045****", "ErrMsg": "", "Token": { "ExpireTime": 1553592564, "Id": "889******166", "UserId": "150**********151" } }
失敗響應(yīng)
HTTP狀態(tài)碼為非200,響應(yīng)字段說明如下表。
參數(shù)
類型
說明
RequestId
String
請求ID
Message
String
失敗響應(yīng)的錯(cuò)誤信息
Code
String
失敗響應(yīng)的錯(cuò)誤碼
說明請根據(jù)錯(cuò)誤碼和錯(cuò)誤信息提示檢查請求參數(shù)是否設(shè)置正確。
以重傳入阿里云賬號(hào)的AccessKey Id錯(cuò)誤為例,響應(yīng)消息如下。
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-CD4365C2****","HostId":"nls-meta.cn-shanghai.aliyuncs.com","Code":"InvalidAccessKeyId.NotFound"}
響應(yīng)體JSON字符串內(nèi)容如下。
{ "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-CD4365C2****", "HostId": "nls-meta.cn-shanghai.aliyuncs.com", "Code": "InvalidAccessKeyId.NotFound" }
簽名機(jī)制
服務(wù)端POP API對每個(gè)接口訪問請求的發(fā)送者都要進(jìn)行身份驗(yàn)證,所以無論使用HTTP協(xié)議還是HTTPS協(xié)議提交的請求,都需要在請求中包含簽名信息。通過簽名機(jī)制,服務(wù)端可以確認(rèn)哪位用戶在做API請求,并能確認(rèn)請求在網(wǎng)絡(luò)傳輸過程中是否被篡改。
安全驗(yàn)證流程:
計(jì)算簽名時(shí),需要阿里云賬號(hào)的AccessKey Id和AccessKey Secret,使用HMAC-SHA1算法進(jìn)行對稱加密。其工作流程如下。
請求端根據(jù)API請求內(nèi)容(包括HTTP請求參數(shù)和請求體)生成簽名字符串。
請求端使用阿里云賬號(hào)的AccessKey Id和AccessKey Secret對第一步生成的簽名字符串進(jìn)行簽名,獲得該API請求的數(shù)字簽名。
請求端把API請求內(nèi)容和數(shù)字簽名一同發(fā)送給服務(wù)端。
服務(wù)端在接收到請求后會(huì)重復(fù)1、2步驟(服務(wù)端會(huì)在后臺(tái)獲取該請求使用的用戶密鑰)并計(jì)算出該請求期望的數(shù)字簽名。
服務(wù)端用期望的數(shù)字簽名和請求端發(fā)送過來的數(shù)字簽名做對比,若完全一致則認(rèn)為該請求通過驗(yàn)證。否則拒絕該請求。
生成請求的簽名字符串:
構(gòu)造規(guī)范化的請求字符串。
將HTTP請求參數(shù)(不包括Signature)構(gòu)造成規(guī)范化的請求字符串。規(guī)范化步驟:
參數(shù)排序。按參數(shù)名的字典順序,對請求參數(shù)進(jìn)行大小寫敏感排序。
參數(shù)編碼。對排序后的請求參數(shù)進(jìn)行規(guī)范化設(shè)置。
請求參數(shù)名和值都要使用
UTF-8
字符集進(jìn)行URL編碼,URL編碼規(guī)則如下:對于字符 A-Z、a-z、0-9以及字符
-
、_
、.
、~
不編碼。對于其他字符編碼成“%XY”的格式,其中XY是字符對應(yīng)ASCII碼的16進(jìn)制表示。比如英文的雙引號(hào)(”)對應(yīng)的編碼就是%22。
對于擴(kuò)展的
UTF-8
字符,編碼成“%XY%ZA…”的格式。需要說明的是英文空格要被編碼為%20,而不是加號(hào)
+
。
說明一般支持URL編碼的庫(比如Java中的java.net.URLEncoder)都是按照“application/x-www-form-urlencoded”的MIME類型的規(guī)則進(jìn)行編碼的。實(shí)現(xiàn)時(shí)可以直接使用此類方式進(jìn)行編碼,然后把編碼后的字符串中:加號(hào)
+
替換為%20
,星號(hào)*
替換為%2A
,%7E
替換為波浪號(hào)~
,即可得到上述規(guī)則描述的編碼字符串。使用等號(hào)
=
連接URL編碼后的參數(shù)名和參數(shù)值:percentEncode(參數(shù)Key) + “=” + percentEncode(參數(shù)值)
。使用與(
&
)號(hào)連接第c步URL編碼后的請求參數(shù)對,如Action=CreateToken&Format=JSON
。說明字符串中第一個(gè)參數(shù)名前面不需要
&
符號(hào)。返回規(guī)范化的請求字符串。
示例如下:
String percentEncode(String value) throws UnsupportedEncodingException { return value != null ? URLEncoder.encode(value, URL_ENCODING) .replace("+", "%20") .replace("*", "%2A") .replace("%7E", "~") : null; } // 對參數(shù)Key排序 String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {}); Arrays.sort(sortedKeys); // 對排序的參數(shù)進(jìn)行編碼、拼接 for (String key : sortedKeys) { canonicalizedQueryString.append("&") .append(percentEncode(key)).append("=") .append(percentEncode(queryParamsMap.get(key))); } queryString = canonicalizedQueryString.toString().substring(1);
說明完整代碼實(shí)現(xiàn)請參見完整示例的
canonicalizedQuery
函數(shù)。構(gòu)造規(guī)范化的請求字符串:
AccessKeyId=LTA******3s2&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=f20b1beb-e5dc-4245-9e96-aa582e905c1a&SignatureVersion=1.0&Timestamp=2019-04-03T03%3A40%3A13Z&Version=2019-02-28
構(gòu)造待簽名字符串。
將HTTP請求的方法(GET)、URL編碼的URL路徑(/)、第1步獲取的規(guī)范化請求字符串使用與(
&
)符號(hào)連接成待簽名字符串:HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(queryString)
。構(gòu)造簽名字符串代碼示例:
StringBuilder strBuilderSign = new StringBuilder(); strBuilderSign.append(HTTPMethod); strBuilderSign.append("&"); strBuilderSign.append(percentEncode(urlPath)); strBuilderSign.append("&"); strBuilderSign.append(percentEncode(queryString)); stringToSign = strBuilderSign.toString();
說明完整代碼實(shí)現(xiàn)請參見完整示例的
createStringToSign
函數(shù)。構(gòu)造的簽名字符串:
GET&%2F&AccessKeyId%3DLTA******F3s%26Action%3DCreateToken%26Format%3DJSON%26RegionID%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Da237e025-07ea-4d87-bb04-d9b2712d871d%26SignatureVersion%3D1.0%26Timestamp%3D2019-04-19T03%253A31%253A40Z%26Version%3D2019-02-28
計(jì)算簽名。
簽名采用HMAC-SHA1算法 + Base64,編碼采用
UTF-8
。根據(jù)AccessKey Secret,將第2步構(gòu)造的待簽名字符串使用HMAC-SHA1算法計(jì)算出對應(yīng)的數(shù)字簽名。其中,計(jì)算簽名時(shí)使用的AccessKey Secret必須在其后面增加一個(gè)與字符
&
。簽名也要做URL編碼。
計(jì)算簽名的代碼示例:
signature = Base64( HMAC-SHA1(stringToSign, accessKeySecret + "&") ); // 進(jìn)行URL編碼 signature = percentEncode(signature)
說明完整代碼實(shí)現(xiàn)請閱讀完整示例的
sign
函數(shù)。計(jì)算得到的簽名:
# 簽名串 AKIktdPUMCV12fTh667BLXeuCtg= # URL編碼后的結(jié)果 AKIktdPUMCV12fTh667BLXeuCtg%3D
計(jì)算簽名后,將簽名的鍵值對用符號(hào)
=
連接,并使用符號(hào)&
添加到第1步獲取的請求字符串中,作為HTTP GET請求參數(shù),發(fā)送到服務(wù)端,獲取Token。String queryStringWithSign = "Signature=" + signature + "&" + queryString;
快速測試
您可以使用以下參數(shù)計(jì)算簽名,比較計(jì)算結(jié)果是否一致。
AccessKey Id和AccessKey Secret沒有提供真實(shí)數(shù)據(jù),Timestamp是過期的時(shí)間,使用這些參數(shù)計(jì)算的簽名,獲取Token時(shí)會(huì)失敗,僅用于計(jì)算簽名測試對比。
AccessKeyId
my_access_key_id
AccessKeySecret:
my_access_key_secret
Timestamp:
2019-04-18T08:32:31Z
SignatureNonce:
b924c8c3-6d03-4c5d-ad36-d984d3116788
請求參數(shù)如下:
AccessKeyId:my_access_key_id
Action:CreateToken
Version:2019-02-28
Timestamp:2019-04-18T08:32:31Z
Format:JSON
RegionId:cn-shanghai
SignatureMethod:HMAC-SHA1
SignatureVersion:1.0
SignatureNonce:b924c8c3-6d03-4c5d-ad36-d984d3116788
規(guī)范化請求字符串。
AccessKeyId=my_access_key_id&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=b924c8c3-6d03-4c5d-ad36-d984d3116788&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Version=2019-02-28
構(gòu)造待簽名字符串。
GET&%2F&AccessKeyId%3Dmy_access_key_id%26Action%3DCreateToken%26Format%3DJSON%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Db924c8c3-6d03-4c5d-ad36-d984d3116788%26SignatureVersion%3D1.0%26Timestamp%3D2019-04-18T08%253A32%253A31Z%26Version%3D2019-02-28
計(jì)算得到簽名。
hHq4yNsPitlfDJ2L0nQPdugdEzM= # URL編碼后的結(jié)果 hHq4yNsPitlfDJ2L0nQPdugdEzM%3D
得到攜帶簽名的請求字符串。
Signature=hHq4yNsPitlfDJ2L0nQPdugdEzM%3D&AccessKeyId=my_access_key_id&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=b924c8c3-6d03-4c5d-ad36-d984d3116788&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Version=2019-02-28
組合成HTTP請求鏈接。
http://nls-meta.cn-shanghai.aliyuncs.com/?Signature=hHq4yNsPitlfDJ2L0nQPdugdEzM%3D&AccessKeyId=my_access_key_id&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=b924c8c3-6d03-4c5d-ad36-d984d3116788&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Version=2019-02-28
替換第5步獲取的HTTP請求鏈接,使用瀏覽器或者curl,獲取Token。
curl "http://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${您的簽名}&AccessKeyId=${您的AccessKey Id}&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=${您的請求UUID}&SignatureVersion=1.0&Timestamp=${您的請求時(shí)間戳}&Version=2019-02-28"
完整示例
本文提供Java、Python語言示例代碼,您可根據(jù)協(xié)議和示例實(shí)現(xiàn)其他語言的客戶端程序。
調(diào)用接口前,需配置環(huán)境變量,通過環(huán)境變量讀取訪問憑證。智能語音交互的AccessKey ID和AccessKey Secret的環(huán)境變量名:ALIYUN_AK_ID和ALIYUN_AK_SECRET。
Java示例
依賴文件:
<!-- http://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>3.9.1</version> </dependency>
示例代碼:
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; /** * 獲取時(shí)間戳 * 必須符合ISO8601規(guī)范,并需要使用UTC時(shí)間,時(shí)區(qū)為+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規(guī)則編碼請求參數(shù)和參數(shù)取值。 */ public static String percentEncode(String value) throws UnsupportedEncodingException { return value != null ? URLEncoder.encode(value, URL_ENCODING).replace("+", "%20") .replace("*", "%2A").replace("%7E", "~") : null; } /*** * 將參數(shù)排序后,進(jìn)行規(guī)范化設(shè)置,組合成請求字符串。 * @param queryParamsMap 所有請求參數(shù) * @return 規(guī)范化的請求字符串 */ 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("規(guī)范化后的請求參數(shù)串:" + queryString); } catch (UnsupportedEncodingException e) { System.out.println("UTF-8 encoding is not supported."); e.printStackTrace(); } return queryString; } /*** * 構(gòu)造簽名字符串 * @param method HTTP請求的方法 * @param urlPath HTTP請求的資源路徑 * @param queryString 規(guī)范化的請求字符串 * @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("構(gòu)造的簽名字符串:" + stringToSign); } catch (UnsupportedEncodingException e) { System.out.println("UTF-8 encoding is not supported."); e.printStackTrace(); } return stringToSign; } /*** * 計(jì)算簽名 * @param stringToSign 簽名字符串 * @param accessKeySecret 阿里云AccessKey Secret加上與號(hào)& * @return 計(jì)算得到的簽名 */ 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("計(jì)算的得到的簽名:" + 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()); } } /*** * 發(fā)送HTTP GET請求,獲取token和有效期時(shí)間戳。 * @param queryString 請求參數(shù) */ public static void processGETRequest(String queryString) { /** * 設(shè)置HTTP GET請求 * 1. 使用HTTP協(xié)議 * 2. Token服務(wù)域名:nls-meta.cn-shanghai.aliyuncs.com * 3. 請求路徑:/ * 4. 設(shè)置請求參數(shù) */ String url = "http://nls-meta.cn-shanghai.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 = System.getenv().get("ALIYUN_AK_ID"); String accessKeySecret = System.getenv().get("ALIYUN_AK_SECRET"); System.out.println(getISO8601Time(null)); // 所有請求參數(shù) Map<String, String> queryParamsMap = new HashMap<String, String>(); queryParamsMap.put("AccessKeyId", accessKeyId); queryParamsMap.put("Action", "CreateToken"); queryParamsMap.put("Version", "2019-02-28"); queryParamsMap.put("Timestamp", getISO8601Time(null)); queryParamsMap.put("Format", "JSON"); queryParamsMap.put("RegionId", "cn-shanghai"); queryParamsMap.put("SignatureMethod", "HMAC-SHA1"); queryParamsMap.put("SignatureVersion", "1.0"); queryParamsMap.put("SignatureNonce", getUniqueNonce()); /** * 1.構(gòu)造規(guī)范化的請求字符串 */ String queryString = canonicalizedQuery(queryParamsMap); if (null == queryString) { System.out.println("構(gòu)造規(guī)范化的請求字符串失敗!"); return; } /** * 2.構(gòu)造簽名字符串 */ String method = "GET"; // 發(fā)送請求的 HTTP 方法,GET String urlPath = "/"; // 請求路徑 String stringToSign = createStringToSign(method, urlPath, queryString); if (null == stringToSign) { System.out.println("構(gòu)造簽名字符串失敗"); return; } /** * 3.計(jì)算簽名 */ String signature = sign(stringToSign, accessKeySecret + "&"); if (null == signature) { System.out.println("計(jì)算簽名失敗!"); return; } /** * 4.將簽名加入到第1步獲取的請求字符串 */ String queryStringWithSign = "Signature=" + signature + "&" + queryString; System.out.println("帶有簽名的請求字符串:" + queryStringWithSign); /** * 5.發(fā)送HTTP GET請求,獲取token。 */ processGETRequest(queryStringWithSign); if (token != null) { System.out.println("獲取的Token:" + token + ", 有效期時(shí)間戳(秒):" + expireTime); // 將10位數(shù)的時(shí)間戳轉(zhuǎn)換為北京時(shí)間 String expireDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(expireTime * 1000)); System.out.println("Token有效期的北京時(shí)間:" + expireDate); } } }
Python示例
說明Python版本要求:Python3.4及以上。
安裝Python HTTP庫Requests:
pip install requests
#!/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': 'cn-shanghai', 'SignatureMethod': 'HMAC-SHA1', 'SignatureNonce': str(uuid.uuid1()), 'SignatureVersion': '1.0', 'Timestamp': time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), 'Version': '2019-02-28'} # 構(gòu)造規(guī)范化的請求字符串 query_string = AccessToken._encode_dict(parameters) print('規(guī)范化的請求字符串: %s' % query_string) # 構(gòu)造待簽名字符串 string_to_sign = 'GET' + '&' + AccessToken._encode_text('/') + '&' + AccessToken._encode_text(query_string) print('待簽名的字符串: %s' % string_to_sign) # 計(jì)算簽名 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) # 進(jìn)行URL編碼 signature = AccessToken._encode_text(signature) print('URL編碼后的簽名: %s' % signature) # 調(diào)用服務(wù) full_url = 'http://nls-meta.cn-shanghai.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 = os.getenv('ALIYUN_AK_ID') access_key_secret = os.getenv('ALIYUN_AK_SECRET') 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有效期的北京時(shí)間:%s' % (time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expire_time))))
相關(guān)文檔
除了OpenAPI方式獲取Token,您還可以通過以下方式獲取Token: