93 lines
3.9 KiB
C#
93 lines
3.9 KiB
C#
|
using Microsoft.Extensions.Options;
|
|||
|
using System.Globalization;
|
|||
|
using System.Security.Cryptography;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace ZeroFramework.IdentityServer.API.Infrastructure.Aliyun
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 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
|
|||
|
/// </summary>
|
|||
|
public class AliyunAuthHandler(IOptions<AlibabaCloudOptions> alibabaCloudOptionsAccessor) : DelegatingHandler
|
|||
|
{
|
|||
|
private readonly AlibabaCloudOptions _alibabaCloudOptions = alibabaCloudOptionsAccessor.Value;
|
|||
|
|
|||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
|||
|
{
|
|||
|
Dictionary<string, string?> 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<string, string?>(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();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|