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呼叫。

驗證碼產生的方式如下:

  1. 以UTF-8格式將指令內容(command string)進行編碼。
  2. 將CaaS / CVPC API呼叫中的指令內容(command string)以”&”符號分隔,可得到多組鍵值/參數對應。
  3. 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

  4. 依據鍵值進行參數排序,重新組合指令內容。(這邊採用自然排序法,即是以字元符號進行排序),排序結果如下:
  5. 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

  6. 將指令內容中的大寫均轉換為小寫,如下:
  7. 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

  8. 搭配Secret Key並使用HMAC SHA-1加密演算法將指令內容進行加密,進一步透過Base64編碼方式將加密結果進行編碼,而編碼結果中可能包含URL之三個特殊字元("+", "/", "="),取代此三個特殊字元後即為驗證碼(signature),取代原則如下表1.,驗證碼格式如下:signature=VBUfKTt48Wf6xbdny98N4Gi07f4。
  9.                     表1.

    原特殊字元
    取代字元
    "+" "*"
    "/" "-"
    "=" ""(空字元)

     

  10. 將驗證碼串於服務平台網址及指令內容後面,即是具驗證功能的CaaS / CVPC API 呼叫。
  11.     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;
	}
}
  • 呼叫說明:
使用上面範例程式碼,可直接透過靜態方法取得有效之CaaS / CVPC API URL,如下:

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該函式庫。