Бекенд на C# Web Api

To Kaiten

JWT аутентификация

Что такое jwt токен

В этом документе я не буду разбирать что такое jwt токен, иначе получится пересказ того что уже хорошо описано в интернете. Если вы не знакомы с тем как работает jwt токен то обязательно почитайте статьи:

Хабр — Подробно про JWT

Хабр — Вы кто такие, я вас не знаю, или Как мы делаем JWT-аутентификацию

Хабр — Токен авторизации на примере JSON WEB Token

Важно будет понять как устроен (из чего состоит) токен, зачем нужно два токена (access и refresh), про время жизни и про то как с этими токенами взаимодействует приложение и клиент.

Flow работы а JWT токенами

В приложении обязательно должно быть два эндпоинта: Login и Refresh. Кратко процесс аутентификации пользователя и работу с токенами можно описать следующими шагами:

  1. Пользователь регистрируется в приложении вводя логин и пароль. Эти данные сохраняются в базе данных.

  2. Пользователь пытается войти в приложение (Login) используя логин и пароль. В случае успеха сервер генерирует два токена и возвращает их пользователю.

  3. Пользователь указывает в заголовке запроса access токен, там где это необходимо.

  4. Когда время жизни access токена истекло, пользователь отправляет запрос на обновление токенов (Refresh). В запрос пользователь отправляет refresh токен. Сервер проверяет корректность refresh токена, генерирует новый access токен и возвращает его пользователю.

  5. Если время жизни refresh токена истекло, пользователь должен заново залогиниться в приложении (Login) чтобы получить новые токены.

Настройка JWT аутентификации в C# Web API

Добавление зависимостей:

В первую очередь необходимо установить следующие пакеты:

Microsoft.AspNetCore.Authentication.JwtBearer

System.IdentityModel.Tokens.Jwt

Регистрация сервиса

В класс ServiceExtentions добавляем метод, в котором настраиваем параметры JWT аутентификации.

public static void AddJwtAuthentication(this IServiceCollection services, IConfiguration config)
{
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(x =>
    {
        x.RequireHttpsMetadata = true;
        x.SaveToken = true;
        x.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidateAudience = false,
            ValidateIssuerSigningKey = true,
            RequireExpirationTime = false,
            ValidateLifetime = true,
            ClockSkew = TimeSpan.Zero,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config["JwtConfig:secret"]))
        };
    });
}

Генерация токенов

Пример класса генерации JWT токена: https://github.com/ArtemVetik/demo-webapi/blob/main/DemoWebApi/Service/JwtTokenService.cs

В данном примере в теле токена хранится id пользователя. В вашей реализации тело токена может быть другим.

Аутентификация пользователя

В приложении должен быть эндпоинт для аутентификации пользователя, например, по почте и паролю. При успешной аутентификации приложение генерирует access и refresh токены и возвращает их пользователю.

public class LoginTokensDto
{
    public string access { get; set; }
    public string refresh { get; set; }
}

...

public async Task<ActionResult<LoginTokensDto>> Login([FromBody] LoginCredentialsDto loginData)
{
    LoginTokensDto loginTokens = await _service.Login(loginData);

    if (loginTokens == null)
        return BadRequest("Invalid credentials");

    return Ok(loginTokens);
}

Использование токена

Для эндпоинтов, доступ к которым нужно ограничить только авторизованным пользователям, необходимо добавить атрибут Authorize. Ниже приведен пример эндпоинта с атрибутом Authorize.

Чтобы выполнить запрос GET /api/profile необходимо передать в заголовке запроса bearer access токен. Если токен невалидный или срок годности токена истек, то метод вернет код ошибки 401 — Unauthorized.

[ApiController]
[Route("api/profile")]
public class ProfileController : ControllerBase
{
    [Authorize]
    [HttpGet]
    public async Task<IActionResult> GetProfile()
    {
        // получаем id из токена
        var playerId = User.FindFirst("id")?.Value;

        if (string.IsNullOrEmpty(playerId))
            return Unauthorized();

        var profileDto = await _service.GetProfile(playerId);

        if (profileDto == null)
            return BadRequest("User not found");

        return Ok(profileDto);
    }
}

Ссылки

Хабр — Подробно про JWT

Хабр — Вы кто такие, я вас не знаю, или Как мы делаем JWT-аутентификацию

Хабр — Токен авторизации на примере JSON WEB Token

Code Maze — JWT Authentication in ASP.NET Core Web API


Автор документа: Артём Ветик