Как правильно разграничить доступ

Есть мидлварь который запрещает доступ по роуту, если пользователь не авторизован

module.exports = async function (req, res, next) {
  try {
    const authorizationHeader = req.headers.authorization;
    if (!authorizationHeader) {
      return next(ApiError.UnauthorizedError());
    }

    const accessToken = authorizationHeader.split(' ')[1]; // отсекаем bearer берём токен
    if (!accessToken) {
      return next(ApiError.UnauthorizedError());
    }

    const userData = await tokenService.validateAccessToken(accessToken);
    if (!userData) {
      return next(ApiError.UnauthorizedError());
    }

    req.user = userData
    next()
  } catch (e) {
    next(ApiError.UnauthorizedError());
  }
};

Но не совсем понимаю как правильно реализовать удаление, редактирование (и тд) элемента, который принадлежит к конкретному юзеру

И в плане структуры, это делается ли это на уровне middleware, или сервиса, или БД?

п.с. - если это имеет значение, в проекте для авторизации используется jsonwebtoken. А так же express и mongoose


Ответы (1 шт):

Автор решения: Dmitriy Grape

Мне известно два пути реализации такого поведения:

  1. CASL Ability. Я отказался от использования этого решения, так как оно не подходило мне по нескольким параметрам: много бойлерплейт кода (В рамках NestJS); не хотелось тянуть лишнюю библиотеку; не известно, какие там есть подводные камни.
  2. Написать всё самому. Я выбрал этот путь.

В вашем случае, как я понял, используется чистый JavaScript, а не TypeScript, что, наверное, усложнит вам жизнь, если вы выберите второй путь, так как я использовал class-transformer, да и в принципе моя реализация была очень зависима от декораторов.

https://github.com/GrapeoffJS/CRMServer/tree/master/apps/crm/src/authorization <--- Если интересно посмотреть мою реализацию авторизации.

Думаю, вам следует почитать документацию у CASL Ability, и, если понравится, то внедрить его.

В моём случае, мне было необходимо скрывать данные от пользователя, а также запрещать доступ к каким-либо действиям в зависимости от его прав, что и потребовало реализации отдельных модулей, которыми будут этим заниматься. А в вашем примере со статьёй на Хабре это можно реализовать и на уровне контроллера, то есть перед удалением или редактированием статьи проверить пользователя на авторство, и, если нет, то выбрасывать res.status(403).end().

export const deletePost = (req, res) => {
   const postId = req.params.id;
   const userId = req.user.id;

   const post = await PostModel.findOne({ id: postId, owner_id: userId });

   if (!post) { return res.status(403).end() }

   return res.json(await PostModel.findByIdAndDelete({ id: postId }));
}
→ Ссылка