首页 > 解决方案 > 如果使用 JWT,如何保护来自访客和角色的路由?

问题描述

在服务器端,我有 2 个中间件 - Protect(已登录?)和 restrictTo(检查用户角色)。如果不允许用户或访客执行某些操作,这些中间件会阻止他们执行某些操作

exports.protect = catchAsync(async (req, res, next) => {
  let token;

  if (
    req.headers.authorization && req.headers.authorization.startsWith("Bearer")
  ) {
    token = req.headers.authorization.split(" ")[1];
  }

  if (!token) {
    return next(new AppError("You are not signed in!", 401));
  }

  const decodedToken = await promisify(jwt.verify)(
    token,
    process.env.JWT_SECRET
  );

  const currentUser = await User.findById(decodedToken.id);
  if (!currentUser) {
    return next(new AppError("User with such token no longer exists"));
  }

  req.user = currentUser;
  next();
});


exports.restrictTo = (...roles) => {
  return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
      return next(new AppError("No access", 403));
    }
    next();
  };
};

但是如何保护客户端的路由呢?如果不允许我发布新笔记,那么我应该被阻止进入/newnote页面,这样我就无法查看和填写表格。JWT 令牌存储在带有 httpOnly 标志的 cookie 中。所以我无法从 Vue 路由器访问令牌。在 Vuex 中存储用户的角色?那么如何在 cookie 和 Vuex 中同步令牌状态呢?如果我的令牌在服务器端被销毁,我仍然可以在 Vuex 中使用它,直到我向受保护的端点发送请求。我应该为受保护的路由请求一个特殊的身份验证端点,以使用 beforeEach 检查我当前的角色吗?

标签: vue.jsvue-router

解决方案


基本上,您应该添加两件事:

  • 存储当前经过身份验证的用户。默认情况下,authUser 为空。当有人登录时,authUser 是一个包含用户数据的对象。您可以将其存储在 Vuex、localStorage 等中。
  • 在您用于 api 请求的任何库中创建一个拦截器/中间件。如果在某个时候您收到 401/403,则表示当前用户的会话已过期,或者他正在尝试访问他不应该查看的受保护区域。无论哪种方式,将本地 authUser 重置为 null 并重定向到登录。

在 Spa/mobile 中,只要您的后端得到适当保护,您就不必为此担心太多。如果您的 authUser 逻辑是正确的,那么只有怀有恶意的用户才会尝试访问保护区,而普通用户将按照规则进行操作,并且永远不会以他们当前的权限访问他们不应该访问的页面(假设 UI 连接正确...... )。


推荐阅读