Аутентификация с помощью JWT
Как доказать личность пользователя на сервере без состояния — подписывать токены, хешировать пароли, защищать маршруты
- объяснить разницу между аутентификацией и авторизацией,
- хешировать и проверять пароли с помощью
bcrypt(никогда не храня открытый текст), - подписывать и проверять JWT с помощью библиотеки
jsonwebtoken, - писать middleware, защищающее приватные маршруты, и понимать реальные компромиссы токенов.
1. Аутентификация и авторизация, и проблема отсутствия состояния
Аутентификация отвечает на вопрос «кто вы?» — вход по электронной почте и паролю. Авторизация отвечает на вопрос «что вам разрешено делать?» — например, только администратор может удалить пользователя. Это разные шаги: сначала вы аутентифицируетесь, затем сервер авторизует каждое действие.
Вот в чём сложность. HTTP не имеет состояния (stateless): каждый запрос существует сам по себе, и сервер не хранит память о предыдущем. Как же после входа второй запрос докажет, что это тот же человек? Два классических ответа:
- Серверные сессии. При входе сервер сохраняет запись сессии и отправляет клиенту случайный идентификатор сессии в cookie. На каждый запрос сервер ищет этот идентификатор в своём хранилище. Просто, но сервер должен помнить каждого вошедшего пользователя, что труднее масштабировать на множество машин.
- Токены (JWT). При входе сервер выдаёт клиенту подписанный токен, который уже содержит личность пользователя. Сервер ничего не хранит; он просто заново проверяет подпись каждый раз. Это аутентификация без состояния, и она масштабируется естественно.
Аналогия. Идентификатор сессии — как номерок в гардеробе: сам по себе номер ничего не значит, и гардероб должен держать список соответствий. JWT — как фестивальный браслет с защищённой от подделки голограммой: сам браслет говорит «взрослый, пропуск на 3 дня», и любой охранник может убедиться, что голограмма настоящая, не звоня в кассу.