Вместо JWT или Cookies, используйте предварительный секрет и некоторые базовые крипто. Используйте их для установки пользовательских заголовков в ваших HTTP-запросах к API Azure из Arduino.
Обязательно храните свой предварительно общий секретный ключ в базе данных и / или переменных среды на компьютере сборки через хранилище ключей Azure - не включайте их в исходный код.
Используйте такой декоратор для защиты ваших контроллеров API:
[UserKeyAuthorize]
public class MyController : Controller
{
// ...
}
Вот реализация атрибута + фильтра:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate)]
public class UserKeyAuthorizeAttribute : TypeFilterAttribute
{
public UserKeyAuthorizeAttribute() : base(typeof(UserKeyFilter))
{
}
public class UserKeyFilter : IAsyncActionFilter
{
public static string CalculateHash(string stringToHash)
{
using (var sha = SHA256.Create())
{
var computedHash = sha.ComputeHash(Encoding.Unicode.GetBytes(stringToHash));
return Convert.ToBase64String(computedHash);
}
}
private const string Hash = "signature";
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// check key
if (!IsUserKeyValid(context.HttpContext.Request))
{
context.Result = new UnauthorizedResult();
}
else
{
await next();
}
}
public static bool IsUserKeyValid(HttpRequest request)
{
var map = new Dictionary<string, string>();
foreach (var header in request.Headers)
{
if (header.Key.StartsWith("x-"))
{
map.Add(header.Key, header.Value);
}
}
var headerSig = "";
foreach (var key in map.OrderBy(x=> x.Key))
{
headerSig = headerSig + "x-" + map[key.Key] + "-";
}
var nonce = request.Headers["nonce"].FirstOrDefault();
headerSig = headerSig + nonce + "-" + Environment.GetEnvironmentVariable("ApiKey");
var hash = CalculateHash(headerSig);
var signature = request.Headers[Hash].FirstOrDefault<string>();
return hash == signature;
}
}
}
На вашем Arduino вы можете затем установить заголовки в ваших запросах API, хешировать их с помощью общего ключа и отправить хеш в качестве дополнительного заголовка, чтобы сервер мог вас проверить. https://github.com/simonratner/Arduino-SHA-256 и https://techtutorialsx.com/2016/07/21/esp8266-post-requests/ должны помочь вам с кодом клиента, вот что работает для меня в C #:
public static async Task<HttpResponseMessage> SignedGetRequest(this HttpClient client, string url, Dictionary<string, string> data)
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
};
var keys = data.Keys.OrderBy(x => x);
var headerSig = "";
foreach (var key in keys)
{
headerSig = headerSig + "x-" + data[key] + "-";
request.Headers.Add("x-" + key, data[key]);
}
// TODO: Time based nonce hash
var nonce = String.Format("{0:r}", DateTime.Now);
headerSig = headerSig + nonce + "-" + Environment.GetEnvironmentVariable("ApiKey");
var hash = Security.CalculateHash(headerSig);
request.Headers.Add("signature", hash);
request.Headers.Add("nonce", nonce);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return await client.SendAsync(request);
}
Вы можете установить любую информацию уровня пользователя или приложения в заголовках, например, например. «x-user-id» для идентификации отдельных клиентов на сервере.
Сведения о настройке ключа в Azure для разрешения Environment.GetEnvironmentVariable("ApiKey")
см. https://stackoverflow.com/a/34622196
.