Использование HMAC с подключенной службой OData
Итак, мы хотим использовать webapi, встроенный в ASP.net и использующий OData в качестве протокола. Я сделал домашнее задание и увидел, что у Microsoft очень хорошая документация.OData Connected Service
. Единственное, что я не могу найти, это то, что веб-интерфейс, который мы хотим использовать, имеет HMAC для безопасности. Я не могу найти пример, гдеOData Connected Service
используется с HMAC. Может ли кто-нибудь объяснить, возможно ли и как HMAC сOData Connected Service
?
1 ответ
Вероятно, ответ зависит от конкретной реализации HMAC на стороне сервера.
Если сервер получает все данные, включенные в запрос, вместе с заголовком авторизации и извлекает значения (идентификатор приложения, подпись, одноразовый номер и отметка времени запроса) из заголовка авторизации, то клиент должен:
Построить строку путем объединения всех данных, которые будут отправлены, эта строка содержит следующие параметры (идентификатор приложения, HTTP - метод, URI запроса, запрос отметки времени, Nonce, и базу 64 строкового представление нагрузки платного запроса).
Подпись будет отправлена в заголовке авторизации с использованием настраиваемой схемы, такой как "amx". Данные в заголовке авторизации будут содержать идентификатор приложения, отметку времени запроса и одноразовый номер, разделенные двоеточием ":". Формат заголовка авторизации будет таким: [Авторизация: amx APPId: Подпись: Одноразовый номер: Отметка времени].
Клиент отправляет запрос как обычно вместе с сгенерированными данными в заголовке авторизации (просто используйте клиентские хуки или 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();
}