CloudStack:"unable to verify user credentials and/or request signature"解決

當我使用HttpClient工具請求CloudStack API時,總是返回401錯誤信息,搗騰了一天,最後還是耐心的解決了這個問題,解決辦法如下:

問題分析:根據提示信息要麼是Api Key寫錯,要麼是生成signature錯誤。

1) Api key問題:

UI界面生成的Api Key Secret Key 會在mysql數據庫中保存,表名爲user,字段名爲api_keysecret_key,我建議複製數據庫裏面的這兩個密鑰值,因爲在頁面複製的api key或者secret key首尾可能會帶有縮進字符,從而在請求的路徑中匹配數據庫裏的密鑰不正確。筆者經歷過。

 

2) Signature問題:

後加入的參數未加入到計算signature的過程中:如下代碼

以上兩個是筆者遇到的問題。

最後經過調整完整版如下:

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;

import yourpackage.utils.HttpClientUtil;//自定義的工具



    @Test
	public void testHttpClientUitl() throws Exception{
		String baseUrl = "http://localhost:8080/client/api?";
		String security = "H65hqe7U-T59TwpD2-0dNYbfcDYKaAnrQQoTFghyiMhMCrGm-pLJV5hGPc8fTHqn6XYxUowJNxjMXxilp4VY2Q";
		String apikey = "2n9_BGYlgUjLZMiHZi5U58_88QCcWLYHwm80WYoc8rd91XMsnlZ4kD9xvg3AMBKpuxz3P8OwOwJhtX-HpelrFg";
		
		TreeMap treeMap = new TreeMap((v1,v2)->{
			if(v1 == null || v2 == null){
				return 0;
			}
			return String.valueOf(v1).compareTo(String.valueOf(v2));
		});
		treeMap.put("command", "listUsers");
		treeMap.put("apiKey", apikey);
		treeMap.put("response", "json");
		StringBuilder str = new StringBuilder();
		treeMap.forEach((k,v)->{
			try {
				String encoded_v = URLEncoder.encode(String.valueOf(v), "UTF-8").replaceAll("\\+", "%20");
				str.append(k).append("=").append(encoded_v).append("&");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		});
		str.replace(str.lastIndexOf("&"), str.length(), "");
		System.out.println(str.toString());
		Mac mac = Mac.getInstance("HmacSHA1");
		SecretKeySpec keySpec =new SecretKeySpec(security.getBytes(),"HmacSHA1");
		mac.init(keySpec);
		mac.update(str.toString().toLowerCase().getBytes());
		byte[] encryptedBytes = mac.doFinal();
		String encodeBase64String = URLEncoder.encode(Base64.encodeBase64String(encryptedBytes), "UTF-8").replaceAll("\\+", "%20");
		System.out.println(encodeBase64String);
		str.append("&signature=").append(encodeBase64String);
		System.out.println(str);
		String httpUrl = baseUrl+str.toString();
		System.out.println(httpUrl);
		HttpClientUtil httpClient = HttpClientUtil.getInstance();
		String reponseContent = httpClient.sendHttpGet(httpUrl);
		System.out.println(reponseContent);
	}

最後,需要注意的是URLEncoder.encode(str)編碼時會將空格轉化爲+號,需要將+號替換爲%20,如下代碼:URLEncoder.encode(str).replaceAll("\\+","%20");

爲什麼轉化爲%20,看以下鏈接查看URL編碼部分知識。

https://www.w3school.com.cn/html/html_urlencode.asp

https://www.w3school.com.cn/tags/html_ref_urlencode.html

以上是筆者在剛開始使用cloudstack調用API的過程中遇到的問題,總結下問題。希望對你有所幫助。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章