Безопасный маршрут доступа с помощью JWT и localstorage

#node.js #express #jwt #ejs

#node.js #экспресс #jwt #ejs

Вопрос:

Я создаю небольшое приложение, в котором пользователь входит в систему и перенаправляется в / profile. Прямо сейчас я извлекаю JWT из localstorage и проверяю его через сервер. Затем сервер отправляет его обратно клиенту, чтобы сообщить мне, является ли это допустимым сеансом или нет.

jQuery / Клиент:

   UserController.initPanel = () => {
    if (session === null) {
     window.location = "/";
    } else {
      UserController.requestAuth(session);
    }
  };

  UserController.requestAuth = (sessionToken) => {
    var settings = {
      "url": "/api/auth", 
      "method": "POST",
      "headers": {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${sessionToken}`,
      },
      "data": ""
    }

    $.ajax(settings).done(function (response) {
      console.log(response);
    });
  };
  

Node.js/auth.js маршрут:

 router.post("/",  (req, res) => {
    const authHeader = req.headers.authorization;
    if (typeof authHeader !== 'undefined') {
        const bearerToken = authHeader.split(' ')[1];
        verifyToken(bearerToken, (authData) => {
            tokenRequest(authData, (authResponse) => {
                handleAuthResponse(req, res, authResponse);
            })
        });
    }
});

const handleAuthResponse = (req, res, authResponse) => {
    console.log(authResponse);
    return res.status(200).json(authResponse);
}


const verifyToken = (token, cb) => {
    jwt.verify(token, 'mysecret', (err, authData) => {
    if (err) {
        res.sendStatus(403)
    } else {
        cb(authData);
    }
    });
}

const tokenRequest = (authHeader, cb) => {
    //console.log(authHeader);
    var config = {
        headers: {'Authorization': `bearer ${authHeader.token}`}
    };
    axios.get('https://myapi.dev/api/session/me', config)
    .then((res) => {
      if (res.data.error) {
        return response.data
      } else {
        cb(res.data);
      }
    })
    .catch((error) => {
      console.log('error', error);
    }); 

}
  

Я чувствую, что это неправильный способ сделать это. Я отрисовываю шаблоны с помощью ejs:

 router.get("/profile", (req, res) => {
  const settings = {
    title: "Profile",
    revslider: false
  };
  res.render("profile/profile", { settings: settings } );
});
  

И если по какой-либо причине JS отключен, /profile все еще доступен. Это не такая уж большая проблема, просто кажется неправильным.

Итак, возможно ли получить доступ к маршруту / профилю, предварительно проверив авторизацию на стороне сервера перед рендерингом?

Кроме того, auth.js возвращает некоторые пользовательские данные, которые я мог бы использовать в шаблоне .ejs. Так что это еще одна причина, по которой я хотел бы попробовать проверить аутентификацию перед рендерингом.

Редактировать:

Промежуточное ПО аутентификации, которое я не использовал, потому что не был уверен, как передать токен?

 module.exports = (req, res, next) => {
    try {
        const decoded = jwt.verify(req.body.token, 'mysecret');
        req.token = decoded;
    } catch (error) {
        console.log(error);
        return res.status(401).json({
            message: 'Auth Failed'
        }); 
    }
    next();
}
  

Комментарии:

1. Как насчет использования промежуточного программного обеспечения в express (при условии, что это то, что вы используете) и примените это ко всем маршрутам, которые вы хотите защитить.

2. У меня был auth в качестве промежуточного программного обеспечения, но я не был уверен, как передать ему токен сеанса.

3. Токен сеанса будет частью запроса, который всегда передается промежуточному программному обеспечению 🙂 хотите, чтобы я написал базовый пример в качестве ответа?

4. Да, пожалуйста @steadweb

5. Извиняюсь, что не перезвонил тебе, Джесс. Используете ли вы следующий пакет для обработки сеансов? npmjs.com/package/express-session

Ответ №1:

Очень простая middleware реализация, ниже которой используются express и express-session .

Мы в основном создаем простую функцию для проверки req.session существования внутри этого объекта, у вас может быть что-то, что определяет, действительно ли пользователь прошел аутентификацию. Я бы рекомендовал вам добавить сюда свою собственную логику для дальнейшей проверки статуса пользователя.

 const authCheckMiddleware = (req, res, next) => {
  // Perform auth checking logic here, which you can attach
  // to any route.
  if(!req.session) {
      return res.redirect('/');
  }

  next();
};
  

authCheckMiddleware Может быть присоединен к любому route , с помощью app.use или router.use . req Объект передается всему промежуточному программному обеспечению.

 // Use the authCheckMiddleware function
router.use('/profile', authCheckMiddleware);
  

Ваш router.get('/profile') вызов теперь защищен вышеупомянутым промежуточным программным обеспечением.

 // Route protected by above auth check middleware
router.get("/profile", (req, res) => {
  const settings = {
      title: "Profile",
      revslider: false
  };

  res.render("profile/profile", { settings: settings } );
});
  

Комментарии:

1. Где «сеанс» проверяет, сохранен ли сеанс через localstorage?

2. Это интерфейс, я концентрируюсь на бэкэнде. Итак, прежде чем вы перейдете к интерфейсу, это должно сработать и перенаправить вас на маршрут входа. Если у вас есть только интерфейсные маршруты, с помощью XHR (AJAX) вам нужно будет вернуть статус 401 и сделать то же самое.