using Microsoft.Extensions.Options; using System.Globalization; using System.Security.Cryptography; using System.Text; namespace ZeroFramework.IdentityServer.API.Infrastructure.Aliyun { /// /// The Alibaba Cloud SDK for .NET allows you to access Alibaba Cloud services such as Elastic Compute Service (ECS), Server Load Balancer (SLB), CloudMonitor, etc. /// You can access Alibaba Cloud services without the need to handle API related tasks, such as signing and constructing your requests. /// https://github.com/aliyun/aliyun-openapi-net-sdk /// public class AliyunAuthHandler(IOptions alibabaCloudOptionsAccessor) : DelegatingHandler { private readonly AlibabaCloudOptions _alibabaCloudOptions = alibabaCloudOptionsAccessor.Value; protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Dictionary parameters = new() { { "SignatureMethod", "HMAC-SHA1" }, { "SignatureNonce", Guid.NewGuid().ToString() }, { "SignatureVersion", "1.0" }, { "AccessKeyId", _alibabaCloudOptions.AccessKeyId }, { "Timestamp", DateTime.Now.ToUniversalTime().ToString("o") }, { "Format", "JSON" } }; foreach (var property in request.Options) { if (property.Value is not null) { var type = property.Value.GetType(); bool isPrimitiveType = type.IsPrimitive || type.IsValueType || (type == typeof(string)); string? propertyValue = isPrimitiveType ? property.Value.ToString() : System.Text.Json.JsonSerializer.Serialize(property.Value); parameters[property.Key] = propertyValue; } } var sortedDictionary = new SortedDictionary(parameters, StringComparer.Ordinal); StringBuilder canonicalizedQueryString = new(); foreach (var p in sortedDictionary) { if (p.Value is not null) { canonicalizedQueryString.Append('&').Append(PercentEncode(p.Key)).Append('=').Append(PercentEncode(p.Value)); } } StringBuilder stringToSign = new(); stringToSign.Append(request.Method).Append('&').Append(PercentEncode("/")).Append('&'); stringToSign.Append(PercentEncode(canonicalizedQueryString.ToString()[1..])); string signature = string.Empty; using (var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(_alibabaCloudOptions.AccessKeySecret + "&"))) { var hashValue = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign.ToString())); signature = Convert.ToBase64String(hashValue); } signature = PercentEncode(signature); request.RequestUri = new Uri($"{request.RequestUri?.Scheme}://{request.RequestUri?.Host}/?Signature={signature}{canonicalizedQueryString}"); return await base.SendAsync(request, cancellationToken); } private static string PercentEncode(string value) { StringBuilder stringBuilder = new(); string text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; byte[] bytes = Encoding.UTF8.GetBytes(value); foreach (char c in bytes) { if (text.Contains(c)) { stringBuilder.Append(c); } else { stringBuilder.Append('%').Append(string.Format(CultureInfo.InvariantCulture, "{0:X2}", (int)c)); } } return stringBuilder.ToString(); } } }