JWT Авторизация для Вашего API на Go

Статья скопирована с www.zhashkevych.com.

Спасибо Максиму – за всё. Смотрите его Ютуб. Музычка. unsplash. Инста. linkedin.

Курс по Go


Система аутентификации является неотъемлемой частью современных веб приложений. Что это такое и какие бывают виды вы скорее всего знаете, а если же нет, то рекомендую ознакомиться самостоятельно. Я не буду углубляться в теорию, ее и так хватает в сети. Сегодня я хочу познакомить вас с распространенным подходом к реализации аутентификации для современных приложений, и реализовать свой сервис на Go.

Интересно? Погнали!

Аутентификация по токенам

С набором популярности микросервисов и облачной инфраструктуры, самым распространенным подходом становиться использование аутентификации по токенам.

Этот подход чаще всего применяется в распределенных системах, где одно приложение (service provider) делегирует аутентификацию другому (identity provider). Суть заключаеться в следующем: identity provider предоставляет достоверные данные пользователя в формате токена, а service provider использует этот токен для аутентификации и авторизации пользователя.

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

Алгоритм действий:

  1. Клиент стучится к identity provider с логином и паролем.
  2. Identity provider находит по соответствующим полям пользователя в своей базе, генерирует токен, срок действия которого истечет через N единиц времени и подписывает его уникальным ключом.
  3. Клиент стучится к бекенду, передавая токен в запросе. Сервер его валидирует, и если токен валидный, разрешает выполнить запрашиваемые действия.

Выглядит это следующим образом.

В качестве примера сервисов аутентификации (identity provider) можно привести Cognito и Identity Platform в экосистемах AWS и GCP соответственно.

Существует несколько форматов токенов: SWT, JWT и SAML. JWT на моей практике это самый распрос
траненный вариант, по этому с ним мы и будем работать далее.

Структура JWT

Давайте начнем с разбора самого JWT токена. По спецификации он содержит 3 блока (заголовки, набор кастомных полей (
claims) и подпись), которые разделены через точку.

Набор полей (claims) содержит произвольные пары имя/значения, однако стоит учитывать что стандарт JWT имеет несколько зарезервированных имен.

Первые два блока представлены в JS
ON-формате и дополнительно закодированы в формат base64.

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

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

Для валидации сервер выполн
яет тот же алгоритм калькуляции хеша подписи, и если они совпадают, считает токен ва
лидным.

Реализация на Go

Для демонстрации данной архитектуры, я написал небольшое REST API, которое позволяет регистрировать новых пользователей и получать токен по уже зарегистрированному логину и паролю. Ознакомиться с проектом вы можете тут.

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

Для работы с JWT мы будем использовать библиотеку github.com/dgrijalva/jwt-go/v4
В Go набор полей для токена объявляется следующим образом.

Структура должна иметь вложеную структуру jwt.StandardClaims, в которой описаны все стандартные поля согласно спецификации JWT. Все остальные поля вы описываете сами.

Теперь перейдем к генерации токена.

В данном методе SignIn() мы ищем пользователя в базе по логину и паролю. Если такая запись существует, генерируем токен, задавая ему также время экспирации.

Теперь давайте рассмотрим метод расшифровки токена.

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

Отлично, мы научились генерировать и парисить JWT токен. Но как реализовать работу с токеном на бекенде?
Токен передается клиентом в формате заголовка Authorization: Bearer . Если заголовок некорректен, АПИ должно отвечать статусом 401 Unauthorized. Если же передан валидный токен, мы даем пользователю доступ до запрашиваемых ресурсов.

Для этого мы напишем простенький middleware. В примере написан обработчик, используя библиотеку gin-gonic/gin.

Как вы можете увидеть, мы достаем токен из HTTP заголовка Authorization: Bearer , а дальше парсим его с помощью функции parser.ParseToken() из пакета github.com/zhashkevych/auth/pkg/parser .

Обратите внимание, функция ParseToken() принимает в качестве аргументов сам токен и ключ, которым был подписан этот токен.

Если вы раньше никогда не работали с аутентификацией, то рекомендую посмотреть исходники данного проекта, а также ознакомиться с примером http-клиента в пакете cmd/example/main.go.

Пишите качественный код и не забывайте про надежную аутентификацию.

Чести и удачи!

Связаться с автором Поддержать автора (что?)

Комментарии

Если у вас есть вопрос, критика или другое мнение - напишите в комментариях.