Интересно? Погнали!
Аутентификация по токенам
С набором популярности микросервисов и облачной инфраструктуры, самым распространенным подходом становиться использование аутентификации по токенам.Этот подход чаще всего применяется в распределенных системах, где одно приложение (service provider) делегирует аутентификацию другому (identity provider). Суть заключаеться в следующем: identity provider предоставляет достоверные данные пользователя в формате токена, а service provider использует этот токен для аутентификации и авторизации пользователя.
Допустим, у нас есть сервис по доставке еды в форме мобильного и веб приложения. Для того чтобы взаимодействовать с бекендом, клиенту необходимо иметь валидный токен.
Алгоритм действий:
- Клиент стучится к identity provider с логином и паролем.
- Identity provider находит по соответствующим полям пользователя в своей базе, генерирует токен, срок действия которого истечет через N единиц времени и подписывает его уникальным ключом.
- Клиент стучится к бекенду, передавая токен в запросе. Сервер его валидирует, и если токен валидный, разрешает выполнить запрашиваемые действия.

Существует несколько форматов токенов: 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 <token>. Если заголовок некорректен, АПИ должно отвечать статусом 401 Unauthorized. Если же передан валидный токен, мы даем пользователю доступ до запрашиваемых ресурсов.
Для этого мы напишем простенький middleware. В примере написан обработчик, используя библиотеку gin-gonic/gin.

Как вы можете увидеть, мы достаем токен из HTTP заголовка Authorization: Bearer <token>, а дальше парсим его с помощью функции parser.ParseToken() из пакета github.com/zhashkevych/auth/pkg/parser .
Обратите внимание, функция ParseToken() принимает в качестве аргументов сам токен и ключ, которым был подписан этот токен.
Если вы раньше никогда не работали с аутентификацией, то рекомендую посмотреть исходники данного проекта, а также ознакомиться с примером http-клиента в пакете cmd/example/main.go.
Пишите качественный код и не забывайте про надежную аутентификацию.
Чести и удачи!