Используйте HMAC с OData Connected Service - PullRequest
0 голосов
/ 01 октября 2019

Итак, мы хотим использовать webapi, который построен на ASP.net и использует OData в качестве протокола. Я сделал домашнее задание и увидел, что у Microsoft очень хороший документ OData Connected Service. Единственное, что я не могу найти, это то, что веб-интерфейс, который мы хотим использовать, имеет HMAC для обеспечения безопасности. Я не могу найти пример, где OData Connected Service используется с HMAC. Может кто-нибудь объяснить, возможно ли и как HMAC с OData Connected Service?

1 Ответ

1 голос
/ 14 октября 2019

Вероятно, ответ зависит от конкретной реализации HMAC на стороне сервера.

Если сервер получает все данные, включенные в запрос вместе с заголовком Authorization и извлекает значения( APP Id , Подпись , Nonce и Метка времени запроса ) из заголовка Авторизация , тогда клиент должен:

  • Создайте строку, объединив все данные, которые будут отправлены, эта строка содержит следующие параметры ( Идентификатор приложения , HTTP-метод , URI запроса , отметка времени запроса , nonce и Представление строки 64 Base полезной нагрузки запроса ).

  • Подпись будет отправлена ​​в заголовке Authorization с использованием пользовательской схемы, такой как «amx». Данные в заголовке авторизации будут содержать APP Id , отметку времени запроса и nonce , разделенные двоеточием ':'. Формат заголовка авторизации будет выглядеть следующим образом: [Авторизация: amx APPId: Подпись: Nonce: метка времени] .

  • Клиент отправляет запрос как обычно вместе ссгенерированные данные в заголовке Authorization (просто используйте клиентские хуки или httpclient ).

Пример (после генерации клиентакод):

private string APPId = "65d3a4f0-0239-404c-8394-21b94ff50604";
private string APIKey = "WLUEWeL3so2hdHhHM5ZYnvzsOUBzSGH4+T3EgrQ91KI=";

public async Task<IEnumerable<string>> TestODataHMAC()
{
    // add there your OData Uri
    var container = new DefaultContainer(new Uri("https://services.odata.org/V4/(S(qc322lduoxrqt13nhydbdcvx))/TripPinServiceRW/")); 
    container.Configurations.RequestPipeline.OnMessageCreating = (args) =>
    {
        var request = new HttpWebRequestMessage(args);

        // Get the Request URI
        string requestUri = HttpUtility.UrlEncode(request.Url.AbsoluteUri.ToLower());

        // Calculate UNIX time
        var epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
        var timeSpan = DateTime.UtcNow - epochStart;
        var requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString();

        // Create the random nonce for each request
        var nonce = Guid.NewGuid().ToString();

        // Creating the raw signature string by combinging
        // APPId, request Http Method, request Uri, request TimeStamp, nonce
        var signatureRawData = string.Format("{0}{1}{2}{3}{4}", APPId, request.Method, requestUri, requestTimeStamp, nonce);

        // Converting the APIKey into byte array
        var secretKeyByteArray = Convert.FromBase64String(APIKey);

        // Converting the signatureRawData into byte array
        var signature = Encoding.UTF8.GetBytes(signatureRawData);

        // Generate the hmac signature and set it in the Authorization header
        using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
        {
            var signatureBytes = hmac.ComputeHash(signature);
            var requestSignatureBase64String = Convert.ToBase64String(signatureBytes);

            //Setting the values in the Authorization header using custom scheme (hmacauth)
            request.SetHeader("Authorization", string.Format("hmacauth {0}:{1}:{2}:{3}", APPId, requestSignatureBase64String, nonce, requestTimeStamp));
        }

        return request;
    };

    // add there your OData method call 
    var nquery = container.People.Where(p => p.Gender == PersonGender.Female).Take(10) as DataServiceQuery<Person>;
    var response = await nquery?.ExecuteAsync();
    return (response as QueryOperationResponse<Person>).Select(p => p.FirstName).ToArray();
}
...