Я только что реализовал это и могу вам с этим помочь:
1 - Я использовал библиотеку starkbank-ecdsa для проверки подписи. 2- Я объявил этот интерфейс
public interface IEmailWebHookRequestValidator
{
bool IsValidRequest([NotNull] HttpRequest request);
}
3- реализация этого интерфейса такова:
public class SendGridWebHookRequestValidator : IEmailWebHookRequestValidator
{
private const string SIGNATURE_HEADER = "X-Twilio-Email-Event-Webhook-Signature";
private const string TIMESTAMP_HEADER = "X-Twilio-Email-Event-Webhook-Timestamp";
private readonly string _sendGridWebHookPublicKey;
public SendGridWebHookRequestValidator(ISettingsProvider settingsProvider)
{
_sendGridWebHookPublicKey = settingsProvider.SendGridWebHookPublicKey //"public key that you can get from SendGrid website when you enable Event Webhook's signature";
}
public bool IsValidRequest([NotNull] HttpRequest request)
{
request.Headers.TryGetValue(SIGNATURE_HEADER, out var signatureHeaderValues);
request.Headers.TryGetValue(TIMESTAMP_HEADER, out var timestampHeaderValues);
var signature = signatureHeaderValues.FirstOrDefault();
var timestamp = timestampHeaderValues.FirstOrDefault();
if (string.IsNullOrWhiteSpace(signature) || string.IsNullOrWhiteSpace(timestamp))
{
return false;
}
var body = ReadStream(request.Body);
return VerifySignature(_sendGridWebHookPublicKey, body, signature, timestamp);
}
public bool VerifySignature(string verificationKey, string payload, string signature, string timestamp)
{
var publicKey = PublicKey.fromPem(verificationKey);
var timestampedPayload = timestamp + payload;
var decodedSignature = Signature.fromBase64(signature);
return Ecdsa.verify(timestampedPayload, decodedSignature, publicKey);
}
public static string ReadStream(Stream stream)
{
using var ms = new MemoryStream();
stream.CopyTo(ms);
return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
}
}
ISettingsProvider - это просто интерфейс, который помогает вам получить ключ publi c из настроек.
Приведенный выше код можно легко использовать, когда ваш веб-перехватчик получает httprequest, просто передав его методу IsValidRequest.