Я создаю веб-приложение, используя стек MERN. Я создал REST API для взаимодействия с моим интерфейсом обычным способом, но я не могу найти лучший способ создать безопасный API и общую безопасность приложения.
Пока это то, что я пробовал
Процесс аутентификации пользователя / запроса:
1. Пользователь вводит учетные данные
2. Сервер отвечает access_token
и refresh_token
, кэшируя refresh_token
в кэше redis с адресом электронной почты в качестве ключа и access_token
в localStorage
3. Для доступа к защищенному маршруту пользователь отправляет запрос с Bearer {ACCESS_TOKEN}
в заголовке запроса
4. Сервер проверяет, действителен ли токен и не истек ли срок его действия , обслуживая пользователя обратно с помощью защищенного ресурса
5. В случае, если срок действия access_token
истек (я оставил срок действия токена коротким, например, 5 минут), действие запускается из внешнего интерфейса (с использованием действий redux ), образец запроса:
POST http://localhost:3000/user/token
Header Bearer {ACCESS_TOKEN}
Body
{
"email" : "user@example.com"
}
Сервер выполняет проверку в кэше Redis, если в электронном письме указано
refresh_token
Если да, сервер отвечает обновленным
access_token
Вот как я подписываю токенов
const signToken = user => {
let email = user.email;
let name = user.name;
const accessToken = JWT.sign({
iss : process.env.APP_NAME,
sub : user.id,
email : email,
name : name
}, JWT_SECRET, {
expiresIn : 300
});
const refreshToken = JWT.sign({
iss : process.env.APP_NAME,
sub : user.id,
email : email,
name : name
}, REFRESH_TOKEN_SECRET, {
expiresIn : '30d'
});
// Save to redis cache
REDIS_CLIENT.set(email, refreshToken);
return {accessToken, refreshToken};
}
и для получения новых access_token
// Refresh token
const refreshToken = (req, res, next) => {
const extractToken = req.headers['authorization'];
const token = extractToken.split(' ')[1];
if (!token) {
return res.status(403).json({
message : 'Unauthorized'
});
}
REDIS_CLIENT.get(req.body.email, (err, cachedToken) => {
if (err) return res.status(500).json({message : 'Something went wrong'});
if (cachedToken == null) {
return res.status(403).json({message : 'Unauthroized'});
} else {
JWT.verify(cachedToken, REFRESH_TOKEN_SECRET, (err, rt) => {
if (err) {
return res.status(500).json({message : 'Something went wrong'})
} else {
// Generate a new access token here
const newAccessToken = JWT.sign({
iss : process.env.APP_NAME,
sub : rt.sub,
email : rt.email,
name : rt.name
}, JWT_SECRET, {
expiresIn : 300
});
return res.json({
"accessToken" : newAccessToken
});
}
});
}
});
}
Безопасен ли этот подход? Если нет, каковы хорошие способы разработать поток аутентификации, если стек равен MERN. При поиске в inte rnet многие советовали установить короткий срок действия в access_token
и использовать refresh_token
для создания нового access_token
, но я не нашел, как выйти из системы при бездействии? Что, если злоумышленник получит просроченный токен и идентификатор электронной почты и сгенерирует новый access_token? Как будет интеграция oAuth?
PS: Извините за то, что выложил здесь так много, зашел сюда после множества поисков по inte rnet, но ничего особенного не нашел