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的过程中遇到的问题,总结下问题。希望对你有所帮助。

 

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