В продолжение предыдущего поста я попытаюсь реализовать систему авторизации с помощью JWT (Json Web Token) для моей многопользовательской игры TicTacToe.
Живой сайт
Исходный код
Что такое JWT
JWT — это авторизационный токен, создаваемый в бэкенде, передаваемый во фронтенд, после чего фронтенд может отправлять этот токен вместе с запросами на доступ к защищенным маршрутам API, это делается для того, чтобы убедиться, что запрос от пользователя X действительно сделан самим пользователем X. Обычно JWT-токен создается со сроком действия.
Здесь есть обратная сторона использования JWT: каждый токен, который был создан и срок действия которого еще не истек, все еще может быть использован для доступа к защищенным маршрутам API. А это обычно не то, чего вы хотели.
Здесь следует сделать небольшую оговорку: Я думаю, что JWT сам по себе очень прост, но его правильная реализация — это самая сложная часть, поэтому если вы знаете лучший способ или у вас есть исправления, пожалуйста, дайте мне знать! Спасибо.
Метод аннулирования JWT
Итак, чтобы аннулировать и ограничить доступ к токену, из того, что я нашел, есть в основном 2 метода:
- Занести токен в черный список/белый список.
- Использовать секретный ключ пользователя для токена.
Честно говоря, я все еще не знаю плюсы/минусы этих методов, но я собираюсь использовать второй.
Создание персонального ключа пользователя
примечание: все приведенные примеры являются упрощенной версией
const bcrypt = require('bcrypt');
function generatePersonalKey() {
return bcrypt.genSaltSync(10);
}
Сначала личный ключ, нам нужно создать функцию для генерации ключей, например, случайных строк, чисел или чего угодно. Но здесь я создал generatePersonalKey()
, используя пакеты bcrypt для создания случайной соли.
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: String,
password: String,
personalKey: String,
});
А в моем UserSchema
(mongoose), например, мы просто инициализируем personalKey при создании пользователя. А когда пользователь выходит из системы, мы просто регенерируем personalKey, таким образом, токены до этого всегда будут недействительны, потому что они использовали другой ключ.
Создание JWT
const jwt = require('jsonwebtoken');
const payload = { username: 'khusyasy' };
const token =
jwt.sign(payload, user.personalKey, {
expiresIn: '1h',
});
Для создания самого токена я использовал пакет jsonwebtoken. На самом деле все очень просто, как показано в примере выше. После этого мы устанавливаем в cookies ответа флаг httpOnly
, чтобы токен нельзя было установить/получить с помощью javascript в браузере.
Проверка авторизации
Когда я впервые прочитал об этом, я очень смутился, как вы узнаете, какой ключ использовать, если вы даже не можете прочитать токен?
Оказывается, можно… просто используя decode
для чтения полезной нагрузки и получения персонального ключа пользователя, а затем используя персональный ключ для проверки самого токена. Например:
const payload = jwt.decode(token);
const user = await User.findOne({ username: payload.username });
try {
const verified = jwt.verify(token, user.personalKey);
// token is verified
} catch (err) {
// token is invalid
}
На сегодня это все, спасибо за чтение!
используемые пакеты:
- bcrypt
- jsonwebtoken
- mongoose