目录
一、HMAC-SHA1
使用 RFC 2104 中定义的 HMAC-SHA1 方法生成带有密钥的哈希值:
private static string CalculateSignature(string secret, string data)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(secret);
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
using (var hmacsha1 = new HMACSHA1(keyBytes))
{
byte[] hashBytes = hmacsha1.ComputeHash(dataBytes);
// 将哈希值转换为十六进制字符串
StringBuilder hexString = new StringBuilder(hashBytes.Length * 2);
foreach (byte b in hashBytes)
{
hexString.AppendFormat("{0:x2}", b);
}
return hexString.ToString();
}
}
二、UriEncode
按照RFC 3986进行 URI 编码:
private static string Rfc3986Encode(string value)
{
// 使用 Uri.EscapeDataString 进行初步编码
var encoded = Uri.EscapeDataString(value);
// 根据 RFC 3986 的要求替换字符
encoded = encoded.Replace("%20", "+");
encoded = encoded.Replace("%21", "!");
encoded = encoded.Replace("%27", "'");
encoded = encoded.Replace("%28", "(");
encoded = encoded.Replace("%29", ")");
encoded = encoded.Replace("%7E", "~ ");
return encoded;
}
三、Date
当前 UTC 时间,以 ISO 8601 yyyyMMddTHHmmssZ 格式表示:
string date = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ");
HTTP 1.1 协议中规定的 GMT 时间:(示例:Wed, 01 Mar 2006 12:00:00 GMT
)
public static string GetCurrentDateTimeInStandardFormat()
{
// 获取当前时间并转换到指定时区
var dateTimeOffset = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(8));
// 将日期时间格式化为字符串
var formattedDateTime = dateTimeOffset.ToString("yyyy-MM-ddTHH:mm:sszzz");
// 替换时区部分的冒号
return formattedDateTime.Substring(0, 22) + formattedDateTime.Substring(23);
}
四、Content-MD5
RFC 1864 定义的请求体(Body) md5 摘要(128 位二进制表示,并使用 base64 编码):
private static string CalculateMD5(byte[] data)
{
using (var md5 = MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(data);
return Convert.ToBase64String(hashBytes);
}
}
五、参数操作
对 URL 中所有参数名、参数值单独 UriEncode
,按参数名字母升序的顺序,依次将参数名、参数值用 =
及 &
拼接:
private static string ConstructCanonicalQueryString(Dictionary<string, string> queryParams)
{
if (queryParams == null || queryParams.Count == 0)
return "";
var sortedQueryParams = queryParams.OrderBy(kvp => kvp.Key);
var encodedQueryParams = sortedQueryParams.Select(kvp => $"{Rfc3986Encode(kvp.Key)}={Rfc3986Encode(kvp.Value)}");
return string.Join("&", encodedQueryParams);
}
六、阿里云API鉴权
下方是阿里云上传文件API鉴权及请求示例(其实接入SDK更方便一些)。(阿里云上传文件后路径为https://桶名称.oss-cn-beijing.aliyuncs.com/文件夹/文件)
using UnityEngine;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using System;
using System.IO;
using UnityEngine.Networking;
public class AliYunManager : MonoBehaviour
{
private const string OSS_HOST = "oss-cn-beijing.aliyuncs.com";//域名
private const string BUCKET_NAME = "*****";//bucket名称
private const string ACCESS_KEY_ID = "************";
private const string ACCESS_KEY_SECRET = "**************";
// Use this for initialization
void Start()
{
UploadFileAsync("D:\\FCJProject\\YiDongYanFaBu\\StudentPartner\\StudentPartner\\Bundles\\StandaloneWindows\\DefaultPackage\\5.0.0\\1ba6bb9f41d66f71f7deb9d2d63b29e4.bundle", "/debug/PC/9.92.0");
}
/// <summary>
///
/// </summary>
/// <param name="imagePath">本地文件绝对路径</param>
/// <param name="bucketPath">需要保存的文件在bucket上的相对路径,前后不需要加'/',也不需要加文件名</param>
public void UploadFileAsync(string filePath, string bucketPath)
{
StartCoroutine(UploadFile(filePath, bucketPath));
}
IEnumerator UploadFile(string filePath, string bucketPath)
{
// Load the image from file
byte[] imageBytes = File.ReadAllBytes(filePath);
string fileName = Path.GetFileName(filePath);
string bucketFilePath = "/" + bucketPath + "/" + fileName;
string url = "https://" + BUCKET_NAME + "." + OSS_HOST + bucketFilePath;
string contentMD5 = "";// ToMD5(imageBytes);
string contentType = "application/octet-stream";
string utcGMT = DateTime.UtcNow.ToString("r");
string canonicalizedOSSHeaders = "";
string canonicalizedResource = "/" + BUCKET_NAME +bucketFilePath;
string authorization = GetAuthorization("PUT", contentMD5, contentType, utcGMT, canonicalizedOSSHeaders, canonicalizedResource);
Debug.Log("Authorization: " + authorization);
Debug.Log("url: " + url);
//Debug.Log("contentMD5: " + contentMD5);
// Create UnityWebRequest
UnityWebRequest request = new UnityWebRequest(url, "PUT");
//request.uploadHandler = new UploadHandlerRaw(imageData);
request.downloadHandler = new DownloadHandlerBuffer();
// Set headers
request.SetRequestHeader("Content-Length", imageBytes.Length.ToString());
request.SetRequestHeader("Content-Type", contentType);
request.SetRequestHeader("Host", BUCKET_NAME + "." + OSS_HOST);
request.SetRequestHeader("Date", utcGMT);
request.SetRequestHeader("Authorization", authorization);
// Set the body of the request
UploadHandlerRaw uploadHandler = new UploadHandlerRaw(imageBytes);
uploadHandler.contentType = contentType;
request.uploadHandler = uploadHandler;
// Send the request and wait for a response
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"Error: {request.error}");
Debug.LogError($"Response Code: {request.responseCode}");
Debug.LogError($"Response Text: {request.downloadHandler.text}");
}
else
Debug.Log(request.downloadHandler.text);
}
private string GetAuthorization(
string method, string contentMD5, string contentType,
string utcGMT, string canonicalizedOSSHeaders, string canonicalizedResource)
{
string data = method + "\n"
+ contentMD5 + "\n"
+ contentType + "\n"
+ utcGMT + "\n"
+ canonicalizedOSSHeaders
+ canonicalizedResource;
Debug.Log("data:"+ data);
string signature = ToHMACSHA1_Base64(ACCESS_KEY_SECRET, data);
string authorization = "OSS " + ACCESS_KEY_ID + ":" + signature;
return authorization;
}
private static string ToHMACSHA1_Base64(string key, string data)
{
using (HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
{
byte[] dataBuffer = Encoding.UTF8.GetBytes(data);
byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
string result = Convert.ToBase64String(hashBytes);
return result;
}
}
private static string ToMD5(byte[] data)
{
using (MD5 md5Hash = MD5.Create())
{
byte[] hashBytes = md5Hash.ComputeHash(data);
Debug.Log(hashBytes.Length);
return Convert.ToBase64String(hashBytes);
}
}
}