签名机制
授权标头计算方法
每个 Azure 内容分发网络 RESTful API 请求都需要进行身份验证,因此请求必须包含身份验证详细信息,并使用 HTTPS 协议。
身份验证信息以授权请求头发送,格式为“AzureCDN {Key ID}:{HMAC-SHA256 signature using Key Value}”。
若要申请和管理密钥 ID 和密钥值,可以使用新版 Azure 内容分发网络管理门户的密钥管理部分。 签名参数部分包括:请求的相对路径、按字母顺序排列并用逗号分隔的查询参数对、请求的 UTC 时间(与请求头中的 x-azurecdn-request-date 相同)以及大写的请求方法。 以上部分用回车换行进行链接,然后使用密钥值进行 HMAC-SHA256 签名。
授权请求头生成示例
Python
def calculate_authorization_header(request_url, request_time, key_id, key_value, http_method):
""" Calculate the authorization header.
@request_url: Complete request URL with scheme, host, path and queries
@request_time: UTC request time with format yyyy-MM-dd HH:mm:ss
@key_id: API key ID
@key_value: API key value
@http_method: Http method in upper case
"""
urlparts = urllib.parse.urlparse(request_url)
queries = urllib.parse.parse_qs(urlparts.query)
ordered_queries = OrderedDict(sorted(queries.items()))
message = "%s\r\n%s\r\n%s\r\n%s" % (urlparts.path, ", ".join(['%s:%s' % (key, value[0]) for (key, value) in ordered_queries.items()]), request_time, http_method)
digest = hmac.new(bytearray(key_value, "utf-8"), bytearray(message, "utf-8"), hashlib.sha256).hexdigest().upper()
return "AzureCDN %s:%s" % (key_id, digest)
Java
/**
* Calculate the authorization header
*
* @param requestURL Complete request URL with scheme, host, path and queries
* @param requestTime UTC request time with format "yyyy-MM-dd HH:mm:ss"
* @param keyID API key ID
* @param keyValue API key value
* @param httpMethod HTTP method in upper case
* @return Calculated authorization header
*/
public static String calculateAuthorizationHeader(String requestURL, String requestTime, String keyID, String keyValue, String httpMethod) throws Exception {
URL url = new URL(requestURL);
String path = url.getPath();
// Get query parameters
String query = url.getQuery();
String[] params = query.split("&");
Map<String, String> paramMap = new TreeMap<String, String>();
for(String param: params) {
String[] paramterParts = param.split("=");
if(paramterParts.length != 2) {
continue;
}
paramMap.put(paramterParts[0], paramterParts[1]);
}
String orderedQueries = paramMap.entrySet()
.stream()
.map(entry -> entry.getKey() + ":" + entry.getValue())
.collect(Collectors.joining(", "));
String content = String.format("%s\r\n%s\r\n%s\r\n%s", path, orderedQueries, requestTime, httpMethod);
Mac sha256HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(keyValue.getBytes(), "HmacSHA256");
sha256HMAC.init(secret_key);
byte[] bytes = sha256HMAC.doFinal(content.getBytes());
StringBuffer hash = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
hash.append('0');
}
hash.append(hex);
}
return String.format("AzureCDN %s:%s", keyID, hash.toString().toUpperCase());
}
Go
func calculateAuthorizationHeader(requestURL, requestTime, keyID, keyValue, httpMethod string) string {
u, err := url.Parse(requestURL)
if err != nil {
panic(err)
}
var path = u.Path
m, _ := url.ParseQuery(u.RawQuery)
var keys []string
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
var orderedQueries []string
for _, k := range keys {
orderedQueries = append(orderedQueries, fmt.Sprintf("%s:%s", k, m[k][0]))
}
var queries = strings.Join(orderedQueries, ", ")
content := fmt.Sprintf("%s\r\n%s\r\n%s\r\n%s", path, queries, requestTime, httpMethod)
hash := hmac.New(sha256.New, []byte(keyValue))
hash.Write([]byte(content))
digest := strings.ToUpper(hex.EncodeToString(hash.Sum(nil)))
return fmt.Sprintf("AzureCDN %s:%s", keyID, digest)
}
C Sharp
/// <summary>
/// Calculate the authorization header.
/// </summary>
/// <param name="requestUrl">Complete request URL with scheme, host, path and queries</param>
/// <param name="requestTime">UTC request time with format yyyy-MM-dd HH:mm:ss.</param>
/// <param name="keyID">The API key ID.</param>
/// <param name="keyValue">The API key value.</param>
/// <param name="httpMethod">Http method in upper case</param>
/// <returns>Calculated authorization header</returns>
public static string CalculateAuthorizationHeader(string requestUrl, string requestTime, string keyID, string keyValue, string httpMethod)
{
Uri requestUri = new Uri(requestUrl);
StringBuilder hashContentBuilder = new StringBuilder();
hashContentBuilder.Append(requestUri.AbsolutePath.ToLowerInvariant());
hashContentBuilder.Append("\r\n");
var queryStrings = HttpUtility.ParseQueryString(requestUri.Query);
var sortedParameterNames = queryStrings.AllKeys.ToList();
sortedParameterNames.Sort((q1, q2) => string.Compare(q1, q2));
var result = string.Join(", ", sortedParameterNames.Select(p => string.Format("{0}:{1}", p, queryStrings[p])).ToArray());
if (!string.IsNullOrEmpty(result))
{
hashContentBuilder.Append(result);
hashContentBuilder.Append("\r\n");
}
hashContentBuilder.Append(requestTime);
hashContentBuilder.Append("\r\n");
hashContentBuilder.Append(httpMethod.ToUpper());
string hashContent = hashContentBuilder.ToString();
using (HMACSHA256 myhmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(keyValue)))
{
byte[] byteArray = Encoding.UTF8.GetBytes(hashContent);
byte[] hashedValue = myhmacsha256.ComputeHash(byteArray);
string sbinary = string.Empty;
for (int i = 0; i < hashedValue.Length; i++)
{
sbinary += hashedValue[i].ToString("X2");
}
return string.Format("AzureCDN {0}:{1}", keyID, sbinary);
}
}