Я ответил на этот вопрос: как обезопасить веб-API ASP.NET 4 года назад с помощью HMAC.
Сейчас многое изменилось в сфере безопасности, особенно JWT становится популярным. Здесь я попытаюсь объяснить, как использовать JWT самым простым и простым способом, каким только могу, чтобы мы не потерялись в джунглях OWIN, Oauth2, ASP.NET Identity ... :).
Если вы не знаете токен JWT, вам нужно немного взглянуть на:
https://tools.ietf.org/html/rfc7519
По сути, токен JWT выглядит так:
<base64-encoded header>.<base64-encoded claims>.<base64-encoded signature>
Пример:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1NzI0LCJleHAiOjE0Nzc1NjY5MjQsImlhdCI6MTQ3NzU2NTcyNH0.6MzD1VwA5AcOcajkFyKhLYybr3h13iZjDyHm9zysDFQ
Токен JWT состоит из трех разделов:
- Заголовок: формат JSON, закодированный в Base64
- Заявки: формат JSON, закодированный в Base64.
- Подпись: создается и подписывается на основе заголовка и утверждений, которые закодированы в Base64.
Если вы используете веб-сайт jwt.io с токеном выше, вы можете декодировать токен и видеть его, как показано ниже:
Технически, JWT использует подпись, которая подписана из заголовков и требует алгоритма безопасности, указанного в заголовках (пример: HMACSHA256). Поэтому JWT необходимо передавать по HTTP, если вы храните какую-либо конфиденциальную информацию в претензиях.
Теперь, чтобы использовать аутентификацию JWT, вам не нужно промежуточное ПО OWIN, если у вас есть устаревшая система Web Api. Простая концепция заключается в том, как предоставить токен JWT и как проверить токен при поступлении запроса. Вот и все.
Перейти к демо, чтобы сохранить JWT токенов легкий, я только хранить username
и expiration time
в JWT. Но таким образом, вам нужно пересоздать новую локальную идентификацию (принципал), чтобы добавить больше информации, например: роли ... если вы хотите выполнить авторизацию ролей. Но если вы хотите добавить больше информации в JWT, вам решать: это очень гибко.
Вместо использования промежуточного программного обеспечения OWIN вы можете просто предоставить конечную точку токена JWT, используя действие контроллера:
public class TokenController : ApiController
{
// This is naive endpoint for demo, it should use Basic authentication
// to provide token or POST request
[AllowAnonymous]
public string Get(string username, string password)
{
if (CheckUser(username, password))
{
return JwtManager.GenerateToken(username);
}
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
public bool CheckUser(string username, string password)
{
// should check in the database
return true;
}
}
Это наивное действие; в производстве вы должны использовать запрос POST или конечную точку базовой аутентификации для предоставления токена JWT.
Как сгенерировать токен на основе username
?
Вы можете использовать пакет NuGet, вызванный System.IdentityModel.Tokens.Jwt
Microsoft, чтобы сгенерировать токен, или даже другой пакет, если хотите. В демо я использую HMACSHA256
с SymmetricKey
:
/// <summary>
/// Use the below code to generate symmetric Secret Key
/// var hmac = new HMACSHA256();
/// var key = Convert.ToBase64String(hmac.Key);
/// </summary>
private const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";
public static string GenerateToken(string username, int expireMinutes = 20)
{
var symmetricKey = Convert.FromBase64String(Secret);
var tokenHandler = new JwtSecurityTokenHandler();
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
}),
Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),
SigningCredentials = new SigningCredentials(
new SymmetricSecurityKey(symmetricKey),
SecurityAlgorithms.HmacSha256Signature)
};
var stoken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(stoken);
return token;
}
Конечная точка для предоставления токена JWT готова. Теперь, как проверить JWT, когда приходит запрос? В демо, которое я построил,
JwtAuthenticationAttribute
который наследует IAuthenticationFilter
(подробнее о фильтре аутентификации здесь ).
С помощью этого атрибута вы можете аутентифицировать любое действие: вам просто нужно поместить этот атрибут в это действие.
public class ValueController : ApiController
{
[JwtAuthentication]
public string Get()
{
return "value";
}
}
Вы также можете использовать промежуточное ПО OWIN или DelegateHander, если вы хотите проверить все входящие запросы для вашего WebAPI (не относится к контроллеру или действию)
Ниже приведен основной метод из фильтра аутентификации:
private static bool ValidateToken(string token, out string username)
{
username = null;
var simplePrinciple = JwtManager.GetPrincipal(token);
var identity = simplePrinciple.Identity as ClaimsIdentity;
if (identity == null)
return false;
if (!identity.IsAuthenticated)
return false;
var usernameClaim = identity.FindFirst(ClaimTypes.Name);
username = usernameClaim?.Value;
if (string.IsNullOrEmpty(username))
return false;
// More validate to check whether username exists in system
return true;
}
protected Task<IPrincipal> AuthenticateJwtToken(string token)
{
string username;
if (ValidateToken(token, out username))
{
// based on username to get more information from database
// in order to build local identity
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username)
// Add more claims if needed: Roles, ...
};
var identity = new ClaimsIdentity(claims, "Jwt");
IPrincipal user = new ClaimsPrincipal(identity);
return Task.FromResult(user);
}
return Task.FromResult<IPrincipal>(null);
}
Рабочий процесс заключается в использовании библиотеки JWT (пакет NuGet выше) для проверки токена JWT, а затем возврата обратно ClaimsPrincipal
. Вы можете выполнить дополнительную проверку, например, проверить, существует ли пользователь в вашей системе, и добавить другие пользовательские проверки, если хотите. Код для проверки токена JWT и возврата принципала:
public static ClaimsPrincipal GetPrincipal(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
if (jwtToken == null)
return null;
var symmetricKey = Convert.FromBase64String(Secret);
var validationParameters = new TokenValidationParameters()
{
RequireExpirationTime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)
};
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
return principal;
}
catch (Exception)
{
//should write log
return null;
}
}
Если токен JWT проверен, а принципал возвращен, вы должны создать новый локальный идентификатор и добавить в него дополнительную информацию для проверки авторизации роли.
Не забудьте добавить config.Filters.Add(new AuthorizeAttribute());
(авторизация по умолчанию) в глобальном масштабе, чтобы предотвратить любые анонимные запросы к вашим ресурсам.
Вы можете использовать Почтальон для тестирования демо:
Запросить токен (наивно, как я уже говорил выше, только для демонстрации)
GET http://localhost:{port}/api/token?username=cuong&password=1
Поместите токен JWT в заголовок авторизованного запроса, например:
GET http://localhost:{port}/api/value
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN1b25nIiwibmJmIjoxNDc3NTY1MjU4LCJleHAiOjE0Nzc1NjY0NTgsImlhdCI6MTQ3NzU2NTI1OH0.dSwwufd4-gztkLpttZsZ1255oEzpWCJkayR_4yvNL1s
Демо-версия размещена здесь: https://github.com/cuongle/WebApi.Jwt.
hmac = new HMACSHA256();var key = Convert.ToBase64String(hmac.Key);
Мне удалось добиться этого с минимальными усилиями (так же просто, как с ASP.NET Core).
Для этого я использую OWIN
Startup.cs
файл иMicrosoft.Owin.Security.Jwt
библиотеку.Чтобы приложение появилось,
Startup.cs
нам нужно изменитьWeb.config
:Вот как
Startup.cs
должно выглядеть:Многие из вас, ребята, используют ASP.NET Core в настоящее время, так что, как вы видите, он не сильно отличается от того, что у нас там есть.
Сначала меня это действительно озадачило, я пытался внедрить пользовательских провайдеров и т. Д. Но я не ожидал, что это будет так просто.
OWIN
просто камни!Стоит упомянуть одну вещь - после того, как я включил OWIN Startup,
NSWag
библиотека перестала работать на меня (например, некоторые из вас могут захотеть автоматически генерировать HTTP-прокси для машинописного текста для приложения Angular).Решение было также очень просто - я заменил
NSWag
сSwashbuckle
и не имеют каких - либо дополнительных вопросов.Хорошо, теперь делимся
ConfigHelper
кодом:Еще один важный аспект - я отправил токен JWT через заголовок авторизации , поэтому машинописный код выглядит для меня следующим образом:
(код ниже генерируется NSWag )
Смотрите часть заголовков -
"Authorization": "Bearer " + localStorage.getItem('token')
источник
I replaced NSWag with Swashbuckle and didn't have any further issues.
У Swashbuckle есть возможность генерировать машинописные файлы или это вы сами добавили?Вот очень минимальная и безопасная реализация аутентификации на основе утверждений с использованием токена JWT в ASP.NET Core Web API.
Прежде всего, вам необходимо предоставить конечную точку, которая возвращает токен JWT с утверждениями, назначенными пользователю:
Теперь вам нужно добавить аутентификацию к вашим услугам в вашем
ConfigureServices
внутреннем ваш startup.cs добавить аутентификацию JWT в качестве службы аутентификации по умолчанию , как это:Теперь вы можете добавить политики к вашим сервисам авторизации, например так:
АЛЬТЕРНАТИВНО , Вы также можете (не обязательно) заполнять все свои заявки из вашей базы данных, поскольку они будут запускаться только один раз при запуске приложения и добавлять их в политики, подобные этой:
Теперь вы можете установить фильтр политики для любого из методов, которые вы хотите авторизовать, например:
Надеюсь это поможет
источник
Я думаю, что вы должны использовать какой-нибудь сторонний сервер для поддержки токена JWT, и в WEB API 2 нет встроенной поддержки JWT.
Однако есть проект OWIN для поддержки некоторого формата подписанного токена (не JWT). Он работает как сокращенный протокол OAuth, предоставляя простую форму аутентификации для веб-сайта.
Вы можете прочитать больше об этом, например, здесь .
Это довольно долго, но большинство деталей - это детали с контроллерами и удостоверением ASP.NET, которые вам могут вообще не понадобиться. Наиболее важными являются
Там вы можете прочитать, как настроить конечную точку (например, "/ token"), к которой вы можете получить доступ из внешнего интерфейса (и подробности о формате запроса).
Другие шаги содержат подробности о том, как подключить эту конечную точку к базе данных и т. Д., И вы можете выбрать необходимые вам части.
источник
В моем случае JWT создается отдельным API, поэтому ASP.NET нужно только декодировать и проверить его. В отличие от принятого ответа мы используем RSA, который является несимметричным алгоритмом, поэтому
SymmetricSecurityKey
упомянутый выше класс не будет работать.Вот результат.
источник