Как проверить jwt токен на валидность
Перейти к содержимому

Как проверить jwt токен на валидность

  • автор:

Пять простых шагов для понимания JSON Web Tokens (JWT)

jwt

Представляю вам мой довольно вольный перевод статьи 5 Easy Steps to Understanding JSON Web Tokens (JWT). В этой статье будет рассказано о том, что из себя представляют JSON Web Tokens (JWT) и с чем их едят. То есть какую роль они играют в проверке подлинности пользователя и обеспечении безопасности данных приложения.

Для начала рассмотрим формальное определение.

JSON Web Token (JWT) — это JSON объект, который определен в открытом стандарте RFC 7519. Он считается одним из безопасных способов передачи информации между двумя участниками. Для его создания необходимо определить заголовок (header) с общей информацией по токену, полезные данные (payload), такие как id пользователя, его роль и т.д. и подписи (signature).
Кстати, правильно JWT произносится как /dʒɒt/

Простыми словами, JWT — это лишь строка в следующем формате header.payload.signature .
Предположим, что мы хотим зарегистрироваться на сайте. В нашем случае есть три участника — пользователь user , сервер приложения application server и сервер аутентификации authentication server . Сервер аутентификации будет обеспечивать пользователя токеном, с помощью которого он позднее сможет взаимодействовать с приложением.

Как приложение использует JWT для проверки аутентификации пользователя.

Приложение использует JWT для проверки аутентификации пользователя следующим образом:

  1. Сперва пользователь заходит на сервер аутентификации с помощью аутентификационного ключа (это может быть пара логин/пароль, либо Facebook ключ, либо Google ключ, либо ключ от другой учетки).
  2. Затем сервер аутентификации создает JWT и отправляет его пользователю.
  3. Когда пользователь делает запрос к API приложения, он добавляет к нему полученный ранее JWT.
  4. Когда пользователь делает API запрос, приложение может проверить по переданному с запросом JWT является ли пользователь тем, за кого себя выдает. В этой схеме сервер приложения сконфигурирован так, что сможет проверить, является ли входящий JWT именно тем, что был создан сервером аутентификации (процесс проверки будет объяснен позже более детально).

Структура JWT

JWT состоит из трех частей: заголовок header , полезные данные payload и подпись signature . Давайте пройдемся по каждой из них.

Шаг 1. Создаем HEADER

Хедер JWT содержит информацию о том, как должна вычисляться JWT подпись. Хедер — это тоже JSON объект, который выглядит следующим образом:

header =

Поле typ не говорит нам ничего нового, только то, что это JSON Web Token. Интереснее здесь будет поле alg , которое определяет алгоритм хеширования. Он будет использоваться при создании подписи. HS256 — не что иное, как HMAC-SHA256 , для его вычисления нужен лишь один секретный ключ (более подробно об этом в шаге 3). Еще может использоваться другой алгоритм RS256 — в отличие от предыдущего, он является ассиметричным и создает два ключа: публичный и приватный. С помощью приватного ключа создается подпись, а с помощью публичного только лишь проверяется подлинность подписи, поэтому нам не нужно беспокоиться о его безопасности.

Шаг 2. Создаем PAYLOAD

Payload — это полезные данные, которые хранятся внутри JWT. Эти данные также называют JWT-claims (заявки). В примере, который рассматриваем мы, сервер аутентификации создает JWT с информацией об id пользователя — userId.

payload =

Мы положили только одну заявку (claim) в payload. Вы можете положить столько заявок, сколько захотите. Существует список стандартных заявок для JWT payload — вот некоторые из них:

  • iss (issuer) — определяет приложение, из которого отправляется токен.
  • sub (subject) — определяет тему токена.
  • exp (expiration time) — время жизни токена.

Эти поля могут быть полезными при создании JWT, но они не являются обязательными. Если хотите знать весь список доступных полей для JWT, можете заглянуть в Wiki. Но стоит помнить, что чем больше передается информации, тем больший получится в итоге сам JWT. Обычно с этим не бывает проблем, но все-таки это может негативно сказаться на производительности и вызвать задержки во взаимодействии с сервером.

Шаг 3. Создаем SIGNATURE

Подпись вычисляется с использование следующего псевдо-кода:

const SECRET_KEY = 'cAtwa1kkEy' const unsignedToken = base64urlEncode(header) + '.' + base64urlEncode(payload) const signature = HMAC-SHA256(unsignedToken, SECRET_KEY)

Алгоритм base64url кодирует хедер и payload, созданные на 1 и 2 шаге. Алгоритм соединяет закодированные строки через точку. Затем полученная строка хешируется алгоритмом, заданным в хедере на основе нашего секретного ключа.

// header eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 // payload eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ // signature -xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM

Шаг 4. Теперь объединим все три JWT компонента вместе

Теперь, когда у нас есть все три составляющих, мы можем создать наш JWT. Это довольно просто, мы соединяем все полученные элементы в строку через точку.

const token = encodeBase64Url(header) + '.' + encodeBase64Url(payload) + '.' + encodeBase64Url(signature) // JWT Token // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM

Вы можете попробовать создать свой собственный JWT на сайте jwt.io.
Вернемся к нашему примеру. Теперь сервер аутентификации может слать пользователю JWT.

Как JWT защищает наши данные?

Очень важно понимать, что использование JWT НЕ скрывает и не маскирует данные автоматически. Причина, почему JWT используются — это проверка, что отправленные данные были действительно отправлены авторизованным источником. Как было продемонстрировано выше, данные внутри JWT закодированы и подписаны, обратите внимание, это не одно и тоже, что зашифрованы. Цель кодирования данных — преобразование структуры. Подписанные данные позволяют получателю данных проверить аутентификацию источника данных. Таким образом закодирование и подпись данных не защищает их. С другой стороны, главная цель шифрования — это защита данных от неавторизованного доступа. Для более детального объяснения различия между кодированием и шифрованием, а также о том, как работает хеширование, смотрите эту статью. Поскольку JWT только лишь закодирована и подписана, и поскольку JWT не зашифрована, JWT не гарантирует никакой безопасности для чувствительных (sensitive) данных.

Шаг 5. Проверка JWT

В нашем простом примере из 3 участников мы используем JWT, который подписан с помощью HS256 алгоритма и только сервер аутентификации и сервер приложения знают секретный ключ. Сервер приложения получает секретный ключ от сервера аутентификации во время установки аутентификационных процессов. Поскольку приложение знает секретный ключ, когда пользователь делает API-запрос с приложенным к нему токеном, приложение может выполнить тот же алгоритм подписывания к JWT, что в шаге 3. Приложение может потом проверить эту подпись, сравнивая ее со своей собственной, вычисленной хешированием. Если подписи совпадают, значит JWT валидный, т.е. пришел от проверенного источника. Если подписи не совпадают, значит что-то пошло не так — возможно, это является признаком потенциальной атаки. Таким образом, проверяя JWT, приложение добавляет доверительный слой (a layer of trust) между собой и пользователем.

В заключение

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

Что дальше?

Подумаем о безопасности и добавим Refresh Token . Смотрите следующую мою статью на эту тему.

Полезные ссылки

  1. 5 Easy Steps to Understanding JSON Web Tokens (JWT)
  2. Securing React Redux Apps With JWT Tokens
  3. Зачем нужен Refresh Token, если есть Access Token?

Как проверить Jwt(Keycloak) на валидность?

Однако SECRET_KEY надо еще получить c Keyckloak.
В правильном ли направлении я иду?
Если да, то никто не знает как получить этот секрет.
——————————————————-
Возможно есть другой, более правильный способ проверить токен доступа.

P.S. Можете скидывать материал или доку. Стараюсь разобраться в материале, но пока тону в нем.

  • Вопрос задан более года назад
  • 361 просмотр

1 комментарий

Средний 1 комментарий

Про токены, JSON Web Tokens (JWT), аутентификацию и авторизацию. Token-Based Authentication

Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор) — это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных.

Авторизация(authorization — разрешение, уполномочивание) — это проверка прав пользователя на доступ к определенным ресурсам.

Например после аутентификации юзер sasha получает право обращатся и получать от ресурса «super.com/vip» некие данные. Во время обращения юзера sasha к ресурсу vip система авторизации проверит имеет ли право юзер обращатся к этому ресурсу (проще говоря переходить по неким разрешенным ссылкам)

  1. Юзер c емайлом sasha_gmail.com успешно прошел аутентификацию
  2. Сервер посмотрел в БД какая роль у юзера
  3. Сервер сгенерил юзеру токен с указанной ролью
  4. Юзер заходит на некий ресурс используя полученный токен
  5. Сервер смотрит на права(роль) юзера в токене и соотвественно пропускает или отсекает запрос

Собственно п.5 и есть процесс авторизации.

Дабы не путатся с понятиями Authentication/Authorization можно использовать псевдонимы checkPassword/checkAccess(я так сделал в своей API)

JSON Web Token (JWT) — содержит три блока, разделенных точками: заголовок(header), набор полей (payload) и сигнатуру. Первые два блока представлены в JSON-формате и дополнительно закодированы в формат base64. Набор полей содержит произвольные пары имя/значения, притом стандарт JWT определяет несколько зарезервированных имен (iss, aud, exp и другие). Сигнатура может генерироваться при помощи и симметричных алгоритмов шифрования, и асимметричных. Кроме того, существует отдельный стандарт, отписывающий формат зашифрованного JWT-токена.

Пример подписанного JWT токена (после декодирования 1 и 2 блоков):

< alg: "HS256", typ: "JWT" >.< iss: "auth.myservice.com", aud: "myservice.com", exp: 1435937883, userName: "John Smith", userRole: "Admin" >.S9Zs/8/uEGGTVVtLggFTizCsMtwOJnRhjaQ2BMUQhcY 

Токены предоставляют собой средство авторизации для каждого запроса от клиента к серверу. Токены(и соотвественно сигнатура токена) генерируются на сервере основываясь на секретном ключе(который хранится на сервере) и payload’e. Токен в итоге хранится на клиенте и используется при необходимости авторизации како-го либо запроса. Такое решение отлично подходит при разработке SPA.

При попытке хакером подменить данные в header’ре или payload’е, токен cтанет не валидным, поскольку сигнатура не будет соответствовать изначальным значениям. А возможность сгенерировать новую сигнатуру у хакера отсутствует, поскольку секретный ключ для зашифровки лежит на сервере.

access token — используется для авторизации запросов и хранения дополнительной информации о пользователе (аля user_id, user_role или еще что либо, эту информацию также называет payload)

refresh token — выдается сервером по результам успешной аутентификации и используется для получения нового access token’a и обновления refresh token’a

Каждый токен имеет свой срок жизни, например access: 30мин, refresh: 60дней

Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли.

Роль рефреш токенов и зачем их хранить в БД. Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут бесконтрольно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).

Схема создания/использования токенов (api/auth/login):

  1. Пользователь логинится в приложении, передавая логин/пароль на сервер
  2. Сервер проверят подлинность логина/пароля, в случае удачи генерирует и отправляет клиенту два токена(access, refresh) и время смерти access token’а ( expires_in поле, в unix timestamp). Также в payloadrefresh token’a добавляется user_id
"accessToken": ". ", "refreshToken": ". ", "expires_in": 1502305985425 
  1. Клиент сохраняет токены и время смерти access token’а, используя access token для последующей авторизации запросов
  2. Перед каждым запросом клиент предварительно проверяет время жизни access token’а (из expires_in )и если оно истекло использует refresh token чтобы обновить ОБА токена и продолжает использовать новый access token

Схема рефреша токенов (api/auth/refresh-tokens):

  1. Клиент проверяет перед запросом не истекло ли время жизни access token’на
  2. Если истекло клиент отправляет на auth/refresh-token URL refresh token
  3. Сервер берет user_id из payload’arefresh token’a по нему ищет в БД запись данного юзера и достает из него refresh token
  4. Сравнивает refresh token клиента с refresh token’ом найденным в БД
  5. Проверяет валидность и срок действия refresh token’а
  6. В случае успеха сервер:
    1. Создает и перезаписывает refresh token в БД
    2. Создает новый access token
    3. Отправляет оба токена и новый expires_in access token’а клиенту

    С такой схемой юзер сможет быть залогинен только на одном устройстве. Тоесть в любом случае при смене устройства ему придется логинится заново.

    Если рассматривать возможность аутентификации на более чем одном девайсе/браузере: необходимо хранить весь список валидных рефреш токенов юзера. Если юзер авторизовался более чем на ±10ти устройствах(что есть весьма подозрительно), автоматически инвалидоровать все рефреш токены кроме текущего и отправлять email с security уведомлением. Как вариант список токенов можно хранить в jsonb(если используется PostgreSQL).

    Схема рефреша токенов (мульти сессии, api/auth/refresh-tokens):

    Для использования возможности аутентификации на более чем одном девайсе необходимо хранить все рефреш токены по каждому юзеру. Я этот список храню в записи юзера в виде JSONB.

    ------------------------------------------------------------------------------------------------- | id | username | refreshTokensMap ------------------------------------------------------------------------------------------------- | 1 | alex | < refreshTokenTimestamp1: 'refreshTokenBody1', refreshTokenTimestamp2: 'refreshTokenBody2'>------------------------------------------------------------------------------------------------- 
    1. Клиент проверяет перед запросом не истекло ли время жизни access token’на
    2. Если истекло клиент отправляет на auth/refresh-token URL refresh token
    3. Сервер берет user_id из payload’arefresh token’a по нему ищет в БД запись данного юзера и достает из него refresh token
    4. Сравнивает refresh token клиента с refresh token’ом найденным в БД
    5. Проверяет валидность и срок действия refresh token’а (но если токен не валиден удаляет его сразу)
    6. В случае успеха сервер:
      1. Удаляет старый рефреш токен
      2. Проверяет количество уже существующих решфреш токенов.
      3. Если их больше 10, удаляет все токены, создает новый и запиывает его в БД.
      4. Если их меньше 10 просто создает и записывает новый в БД.
      5. Создает новый access token
      6. Отправляет оба токена и новый expires_in access token’а клиенту

      Таким образом если юзер залогинился на пяти устройствах, рефреш токены будут постоянно обновлятся и все счастливы. Но если с аккаунтом юзера начнут производить подозрительные действия(попытаются залогинится более чем на 10ти устройствах) система сбросит все сессии(рефреш токены) кроме последней.

      Как дополнительная мера можно вообще заблокировать данного юзера при попытке залогинится более чем на 10ти устройствах. С возможностью разблокировки только через email. Но в этом случае нам необходимо будет во время каждого рефреша проверять список токенов на наличие мертвых(не валидных).

      Ключевой момент:

      В момент рефреша то есть обновления access token’a обновляются ОБА токена. Но как же refresh token может сам себя обновить, он ведь создается только после успешной аунтефикации ? refresh token в момент рефреша сравнивает себя с тем refresh token’ом который лежит в БД и вслучае успеха, а также если у него не истек срок, система рефрешит токены. Внимание при обновлении refresh token’a продливается также и его срок жизни.

      Возникает вопрос зачем refresh token’y срок жизни, если он обновляется каждый раз при обновлении access token’a ? Это сделано на случай если юзер будет в офлайне более 60 дней, тогда прийдется заново вбить логин/пароль.

      В случае кражи(обоих токенов):

      1. Хакер воспользовался access token’ом
      2. Закончилось время жизни access token’на
      3. Клиент хакера отправляет refresh token
      4. Хакер получает новую пару токенов
      5. На сервере создается новая пара токенов(«от хакера»)
      6. Юзер пробует зайти на сервер >> обнаруживается что токены невалидны
      7. Сервер перенаправляет юзера на форму аутентификации
      8. Юзер вводит логин/пароль
      9. Создается новая пара токенов >> пара токенов «от хакера» становится не валидна

      Проблема: Поскольку refresh token продлевает срок своей жизни каждый раз при рефреше токенов >> хакер пользуется токенами до тех пор пока юзер не залогинится.

      В случае паранои:

      • хранить список валидных IP, deviceID, fingerprint браузера, генерить рандомный randomUserID
      • дополнительно шифровать токены (в nodejs например crypt >> aes-256)
      • зашивать в payload также IP/подсеть владельца токена. В этом случае при каждой попытке зайти с новой точки доступа к интерету придется перелогиниватся.

      Как проверить jwt токен на валидность

      Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

      Последнее обновление: 27.12.2019

      Общие подходы к авторизации и аутентификации в ASP.NET Core Web API несколько отличаются от того, что мы имеем в MVC. В частности, в Web API механизм авторизации полагается преимущественно на JWT-токены. Что такое JWT-токен?

      JWT (или JSON Web Token) представляет собой веб-стандарт, который определяет способ передачи данных о пользователе в формате JSON в зашифрованном виде.

      JWT-токен состоит из трех частей:

      • Header — объект JSON, который содержит информацию о типе токена и алгоритме его шифрования
      • Payload — объект JSON, который содержит данные, нужные для авторизации пользователя
      • Signature — строка, которая создается с помощью секретного кода, Headera и Payload. Эта строка служит для верификации токена

      Для использования JWT-токенов создадим новый проект ASP.NET Core по типу Empty .

      JWT Token in ASP.NET Core Web API

      Далее добавим в проект папку Models , в которой определим новый класс Person :

      public class Person < public string Login < get; set; >public string Password < get; set; >public string Role < get; set; >>

      Этот класс будет описывать учетные записи пользователей в приложении.

      Для работы с JWT-токенами установим через Nuget пакет Microsoft.AspNetCore.Authentication.JwtBearer .

      Также добавим в проект специальный класс AuthOptions , который будет описывать ряд свойств, нужных для генерации токена:

      using Microsoft.IdentityModel.Tokens; using System.Text; namespace TokenApp < public class AuthOptions < public const string ISSUER = "MyAuthServer"; // издатель токена public const string AUDIENCE = "MyAuthClient"; // потребитель токена const string KEY = "mysupersecret_secretkey!123"; // ключ для шифрации public const int LIFETIME = 1; // время жизни токена - 1 минута public static SymmetricSecurityKey GetSymmetricSecurityKey() < return new SymmetricSecurityKey(Encoding.ASCII.GetBytes(KEY)); >> >

      Константа ISSUER представляет издателя токена. Здесь можно определить любое название. AUDIENCE представляет потребителя токена — опять же может быть любая строка, но в данном случае указан адрес текущего приложения.

      Константа KEY хранит ключ, который будет применяться для создания токена.

      Для встраивания функциональности JWT-токенов в конвейер обработки запроса используется компонент JwtBearerAuthenticationMiddleware . Так, изменим класс Startup следующим образом:

      using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; namespace TokenApp < public class Startup < public void ConfigureServices(IServiceCollection services) < services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options =>< options.RequireHttpsMetadata = false; options.TokenValidationParameters = new TokenValidationParameters < // укзывает, будет ли валидироваться издатель при валидации токена ValidateIssuer = true, // строка, представляющая издателя ValidIssuer = AuthOptions.ISSUER, // будет ли валидироваться потребитель токена ValidateAudience = true, // установка потребителя токена ValidAudience = AuthOptions.AUDIENCE, // будет ли валидироваться время существования ValidateLifetime = true, // установка ключа безопасности IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(), // валидация ключа безопасности ValidateIssuerSigningKey = true, >; >); services.AddControllersWithViews(); > public void Configure(IApplicationBuilder app) < app.UseDeveloperExceptionPage(); app.UseDefaultFiles(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints =>< endpoints.MapDefaultControllerRoute(); >); > > >

      Для установки аутентификации с помощью токенов в методе ConfigureServices в вызов services.AddAuthentication передается значение JwtBearerDefaults.AuthenticationScheme . Далее с помощью метода AddJwtBearer() добавляется конфигурация токена.

      Для конфигурации токена применяется объект JwtBearerOptions , который позволяет с помощью свойств настроить работу с токеном. В данном случае использованы следующие свойства:

      • RequireHttpsMetadata : если равно false, то SSL при отправке токена не используется. Однако данный вариант установлен только дя тестирования. В реальном приложении все же лучше использовать передачу данных по протоколу https.
      • TokenValidationParameters : параметры валидации токена — сложный объект, определяющий, как токен будет валидироваться. Этот объект в свою очередь имеет множество свойств, которые позволяют настроить различные аспекты валидации токена. Но наиболее важные свойства: IssuerSigningKey — ключ безопасности, которым подписывается токен, и ValidateIssuerSigningKey — надо ли валидировать ключ безопасности. Ну и кроме того, можно установить ряд других свойств, таких как нужно ли валидировать издателя и потребителя токена, срок жизни токена, можно установить название claims для ролей и логинов пользователя и т.д.

      Теперь мы можем использовать авторизацию на основе токенов. Однако в прокте пока не предусмотрена генерация токенов. По умолчанию в ASP.NET Core отсутствуют встроенные возможности для создания токена. И в данном случае мы можем либо воспользоваться сторонними решениями (например, IdentityServer или OpenIdDict), либо же создать свой механизм. Выберем второй способ.

      Создадим в проекте новую папку Controllers и добавим в нее новый контроллер AccountController :

      using System; using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using TokenApp.Models; // класс Person namespace TokenApp.Controllers < public class AccountController : Controller < // тестовые данные вместо использования базы данных private Listpeople = new List < new Person , new Person < Login="qwerty@gmail.com", Password="55555", Role = "user" >>; [HttpPost("/token")] public IActionResult Token(string username, string password) < var identity = GetIdentity(username, password); if (identity == null) < return BadRequest(new < errorText = "Invalid username or password." >); > var now = DateTime.UtcNow; // создаем JWT-токен var jwt = new JwtSecurityToken( issuer: AuthOptions.ISSUER, audience: AuthOptions.AUDIENCE, notBefore: now, claims: identity.Claims, expires: now.Add(TimeSpan.FromMinutes(AuthOptions.LIFETIME)), signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(), SecurityAlgorithms.HmacSha256)); var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); var response = new < access_token = encodedJwt, username = identity.Name >; return Json(response); > private ClaimsIdentity GetIdentity(string username, string password) < Person person = people.FirstOrDefault(x =>x.Login == username && x.Password == password); if (person != null) < var claims = new List< new Claim(ClaimsIdentity.DefaultNameClaimType, person.Login), new Claim(ClaimsIdentity.DefaultRoleClaimType, person.Role) >; ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, "Token", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); return claimsIdentity; > // если пользователя не найдено return null; > > >

      Для упрощения ситуации данные пользователей определены в виде простого списка. Для поиска пользователя в этом списке по логину и паролю определен метод GetIdentity() , который возвращает объект ClaimsIdentity.

      Принцип создания ClaimsIdentity здесь тот же, что и при аутентификации с помощью кук: создается набор объектов Claim, которые включают различные данные о пользователе, например, логин, роль и т.д.

      Для обработки запроса в контроллере создан метод Token, который сопоставлен с маршрутом «/token». Этот метод обрабатывает запросы POST и через параметры принимает логин и пароль пользователя.

      Сам токен представляет объект JwtSecurityToken , для инициализации которого применяются все те же константы и ключ безопасности, которые определены в классе AuthOptions и которые использовались в классе Startup для настройки JwtBearerAuthenticationMiddleware. Важно, чтобы эти значения совпадали.

      С помощью параметра claims: identity.Claims в токен добавляются набор объектов Claim, которые содержат информацию о логине и роли пользователя.

      Далее посредством метода JwtSecurityTokenHandler().WriteToken(jwt) создается Json-представление токена. И в конце он сериализуется и отправляет клиенту с помощью метода Json() .

      Таким образом генерируется токен.

      Для тестирования токена создадим простенький контроллер ValuesController:

      using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; namespace TokenApp.Controllers < [ApiController] [Route("api/[controller]")] public class ValuesController : Controller < [Authorize] [Route("getlogin")] public IActionResult GetLogin() < return Ok($"Ваш логин: "); > [Authorize(Roles = "admin")] [Route("getrole")] public IActionResult GetRole() < return Ok("Ваша роль: администратор"); >> >

      И в конце добавим в проект для статических файлов папку wwwroot , а в нее — новый файл index.html :

          JWT в ASP.NET Core Web API   

      Вы вошли как:

      Вход на сайт







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

      После нажатия кнопки на форме логина запрос будет отправляться методом POST на адрес «/token». Поскольку за обработку запросов по этому маршруту отвечает метод Token контроллера AccountController, по результатам работы которого будет формироваться токен.

      Ответом сервера в случае удачной аутентификации будет примерно следующий объект:

      Параметр access_token как раз и будет представлять токен доступа. Также в объекте передается дополнительная информация о нике пользователя.

      Для того, чтобы в коде js данный токен в дальнейшем был доступен, то он сохраняется в хранилище sessionStorage.

      Последние два блока предназначены для отправки запросов к методам ValuesController. Чтобы отправить токен в запросе, нам нужно настроить в запросе заголовок Authorization:

      headers: < "Accept": "application/json", "Authorization": "Bearer " + token // передача токена в заголовке >

      В итоге весь проект будет выглядеть следующим образом:

      JWT в ASP.NET Core Web API

      По ранее сохраненному ключу получаем из хранилища sessionStorage токен и формируем заголовок.

      Теперь после получения токена мы можем осуществить запрос к методам контроллера ValuesController:

      Роли в токене JWT в ASP.NET Core Web API

      В то же время если мы попробуем обратиться к тем же методам без токена или с токеном с истекшим сроком, то получим ошибку 401 (Unauthorized).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *