API呼叫授權認證
上次更新時間: 2020/09/25
透過HTTP或HTTPS的GET方式進行CaaS / CVPC API的呼叫時,需在HTTP Query String中加入認證相關參數,當CaaS / CVPC API服務平台接收到此呼叫時,會進一步驗證該呼叫是否帶有合法之驗證碼(signature)。客戶需事先於CloudBOSS 雲端服務系統入口網站上取得一組合法的CaaS / CVPC API Key,包含Access Key及Secret Key,以便透過運算出驗證碼。
以下為一CaaS / CVPC API呼叫的實際範例:
https://hws.hicloud.hinet.net/cloud_hws/api/hws/?action=runInstances&version=2013-03-29 &chtAuthType=hwspass&imageId=hi-olajtpss&instanceType=HC1.S.LINUX&monitoringEnabled=false &instanceName=haha&count=1&accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0 &expires=2013-03-29T17:50:04Z&signature=VBUfKTt48Wf6xbdny98N4Gi07f4
拆解上列呼叫實例,說明如下。
- 服務平台網址(basic url):
https://hws.hicloud.hinet.net/cloud_hws/api/hws/?
- 指令內容(command string):
action=runInstances&version=2013-03-29&chtAuthType=hwspass&imageId=hi-olajtpss&instanceType=HC1.S.LINUX&monitoringEnabled=false&instanceName=haha&count=1&accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0&expires=2013-03-29T17:50:04Z
- 驗證碼(signature):
signature=VBUfKTt48Wf6xbdny98N4Gi07f4
每個CaaS / CVPC API呼叫,均以服務平台網址(basic url)、指令內容(command string)、驗證碼(signature)的內容串接起來,才可視為一有效的CaaS / CVPC API呼叫。
驗證碼產生的方式如下:
- 以UTF-8格式將指令內容(command string)進行編碼。
- 將CaaS / CVPC API呼叫中的指令內容(command string)以”&”符號分隔,可得到多組鍵值/參數對應。
- 依據鍵值進行參數排序,重新組合指令內容。(這邊採用自然排序法,即是以字元符號進行排序),排序結果如下:
- 將指令內容中的大寫均轉換為小寫,如下:
- 搭配Secret Key並使用HMAC SHA-1加密演算法將指令內容進行加密,進一步透過Base64編碼方式將加密結果進行編碼,而編碼結果中可能包含URL之三個特殊字元("+", "/", "="),取代此三個特殊字元後即為驗證碼(signature),取代原則如下表1.,驗證碼格式如下:signature=VBUfKTt48Wf6xbdny98N4Gi07f4。
- 將驗證碼串於服務平台網址及指令內容後面,即是具驗證功能的CaaS / CVPC API 呼叫。
action=runInstances
version=2013-03-29
imageId=hi-olajtpss
instanceType=HC1.S.LINUX
monitoringEnabled=false
instanceName=haha
count=1
accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0
expires=2013-03-29T17:50:04Z
accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0&action=runInstances&chtAuthType=hwspass&count=1&expires=2013-03-29T17:50:04Z&imageId=hi-olajtpss&instanceName=haha&instanceType=HC1.S.LINUX&monitoringEnabled=false&version=2013-03-29
accesskey=u0u0mu5uqxhnref3tvrfek5qstvprfkxturneu1uwt0&action=runinstances&chtauthtype=hwspass&count=1&expires=2013-03-29t17:50:04z&imageid=hi-olajtpss&instancename=haha&instancetype=hc1.s.linux&monitoringenabled=false&version=2013-03-29
表1.
原特殊字元 |
取代字元 |
---|---|
"+" | "*" |
"/" | "-" |
"=" | ""(空字元) |
https://hws.hicloud.hinet.net/cloud_hws/api/hws/?action=runInstances &version=2013-03-29&chtAuthType=hwspass &imageId=hi-olajtpss&instanceType=HC1.S.LINUX&monitoringEnabled=false&instanceName=haha &count=1&accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0&expires=2013-03-29T17:50:04Z &signature=VBUfKTt48Wf6xbdny98N4Gi07f4
使用hws-signature Java函式取得驗證碼
- 以下是透過JAVA程式產生驗證碼之範例程式:
package chttl.cloud.hws; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; public class HWSSignature { /** * Generate signature from your secret key and URL format string. * And use the Overload mechanism to call "generateSignature(String userSecretKey, String commandString)" method for the return value * @param String userSecretKey * @param String unsignedUrl * @return String URL */ public static String getSignedUrl(String userSecretKey, String unsignedUrl){ String commandString =unsignedUrl.substring(unsignedUrl.indexOf('?') + 1); return unsignedUrl + "&signature=" + generateSignature(userSecretKey, commandString); } /** * Generate signature string from your secret key string and the command string. * And use the Overload mechanism to call "generateSignature(String userSecretKey, Map<String, List<String>> arguments)" method for the return value. * @param String userSecretKey * @param String commandString * @return String signature */ public static String generateSignature(String userSecretKey, String commandString) { Map<String, List<String>> arguments = new HashMap<String, List<String>>(); String decodedUrl = ""; try { decodedUrl = URLDecoder.decode(commandString, "utf8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } String [] commands = decodedUrl.split("&"); for(String command : commands) { String [] keyValues = command.split("="); if(arguments.containsKey(keyValues[0])){ List<String> valueList=arguments.get(keyValues[0]); valueList.add(keyValues[1]); }else{ List<String> valueList = new ArrayList<String>(); valueList.add(keyValues[1]); arguments.put(keyValues[0], valueList); } } return generateSignature(userSecretKey, arguments); } /** * Generate signature string from your secret key string and Map object which is composed of command pairs. * But the "arguments" hash map should not contain "signature" key entry. * @param String userSecretKey * @param Map<String, List<String>> arguments * @return String mySignature */ public static String generateSignature(String userSecretKey, Map<String, List<String>> arguments){ List<String> argumentNameList = new ArrayList<String>(); String mySignature = null; for(String name : arguments.keySet()) { argumentNameList.add(name); } Collections.sort(argumentNameList); String requestMsg = null; for(String argumentName : argumentNameList){ List<String> valueList = arguments.get(argumentName); for(int listCount=0 ; listCount<valueList.size() ; listCount++){ if(requestMsg == null){ requestMsg = argumentName + "=" + valueList.get(listCount); }else { requestMsg += "&" + argumentName + "=" + valueList.get(listCount); } } } requestMsg = requestMsg.toLowerCase(); System.out.println(requestMsg); try { Mac mac; mac = Mac.getInstance("HmacSHA1"); SecretKeySpec keySpec = new SecretKeySpec(userSecretKey.getBytes(), "HmacSHA1"); mac.init(keySpec); mac.update(requestMsg.getBytes()); byte[] encryptedBytes = mac.doFinal(); mySignature = getBase64String(encryptedBytes); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return mySignature; } /** * Generate Base64 encoded string from the byte buffer. * Handle and prevent URL from containing the special characters * @param byte[] encryptedBytes * @return String encodeString */ private static String getBase64String(byte[] encryptedBytes) { String encodeString = null; encodeString = new String(Base64.encodeBase64(encryptedBytes)); encodeString = encodeString.replace("+", "*"); encodeString = encodeString.replace("/", "-"); encodeString = encodeString.replace("=", ""); return encodeString; } }
- 呼叫說明:
HWSSignature.getSignedUrl(" your secretKey "," https://CaaS / CVPC API basic url/?command string "));
呼叫實例:
HWSSignature.getSignedUrl("WWpJNU16a3pOV1JsWWpNeU5HVXdOMkkxTURNd1lUbG1OMlEwTXpSaFptST0",
"https://hws.hicloud.hinet.net/cloud_hws/api/hws/?action=runInstances&version=2013-03-29&chtAuthType=hwspass&imageId=hi-olajtpss&instanceType=HC1.S.LINUX&monitoringEnabled=false&instanceName=haha&count=1&accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0&expires=2013-03-29T17:50:04Z");
輸出:
https://hws.hicloud.hinet.net/cloud_hws/api/hws/?action=runInstances&version=2013-03-29&chtAuthType=hwspass&imageId=hi-olajtpss&instanceType=HC1.S.LINUX&monitoringEnabled=false&instanceName=haha&count=1&accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0&expires=2013-03-29T17:50:04Z&signature=VBUfKTt48Wf6xbdny98N4Gi07f4
也可以透過 HWSSignature.generateSignature(" your secretKey ","command string "),取得驗證碼
呼叫實例:
HWSSignature.generateSignature("WWpJNU16a3pOV1JsWWpNeU5HVXdOMkkxTURNd1lUbG1OMlEwTXpSaFptST0",
"action=runInstances&version=2013-03-29&chtAuthType=hwspass&imageId=hi-olajtpss&instanceType=HC1.S.LINUX&monitoringEnabled=false&instanceName=haha&count=1&accessKey=U0U0MU5UQXhNREF3TVRFek5qSTVPRFkxTURneU1UWT0&expires=2013-03-29T17:50:04Z")
輸出:
VBUfKTt48Wf6xbdny98N4Gi07f4
Note. 本範例程式使用Apache common code進行Base64編碼,使用時需import該函式庫。