【问题标题】:How can i identify if user is admin or not in Express?如何在 Express 中识别用户是否为管理员?
【发布时间】:2021-03-13 09:27:46
【问题描述】:

早安,

我正在尝试创建一个客户端和管理员都可以登录的登录系统。如果用户是管理员,那么他/她将被重定向到管理面板,如果不是,那么用户将被重定向到主页网上商店的页面。我在身份验证的逻辑上有点挣扎。我正在尝试确定用户是否已登录。如果/她是,那么我通过检查“isAdmin”是真还是假来验证用户角色。我通过查找 isAdmin 状态在数据库中查找用户来做到这一点。我正在使用 jwt 令牌来获取用户的状态。

身份验证:

const { verify } = require("jsonwebtoken");
const userModel = require("../model/userModel");

// const isAuth = req => {
//  const authorization = req.headers["authorization"];
//  if (!authorization) throw new Error("You need to login");
//  const token = authorization.split(" ")[1];
//  const { userId } = verify(token, process.env.ACCESS_TOKEN_SECRET);
//  return userId;
// };

const isAuth = (req, res, next) => {
    const token = req.header("auth-token");
    if (!token) return res.status(401).send("Access denied");
    //verifying the token then  sending the id back of the user
    try {
        const verified = verify(token, process.env.SECRET);
        req.user = verified;
        next();
    } catch (err) {
        res.status(400).send("Invalid");
    }
};

//isAdmin
const isAdmin = async (req, res, next) => {
    const token = req.header("auth-token");
    if (!token) return res.status(401).send("No User");
    try {
        const verified = verify(token, process.env.SECRET);
        req.user = verified;
        let user = await userModel.findOne({ isAdmin });
        if (req.user && user.isAdmin === true) {
            return next();
        }
    } catch (err) {
        return res.status(401).send({ msg: "Admin token is not valid" });
    }
};

//check user
// const checkUser = (req, res, next) => {
//  //get token from cookies
//  const token = req.cookies.jwt;
//  //check if token exists
//  if (token) {
//      verify(token, process.env.SECRET, async (err, decode) => {
//          if (err) {
//              console.log(err.message);
//              next();
//              res.locals.user = null;
//          } else {
//              console.log(decode);
//              next();
//              let user = await userModel.findOne(decode.isAdmin);
//              res.local.user = user;
//              next();
//          }
//      });
//  } else {
//  }
// };

module.exports = {
    isAuth,
    isAdmin,
};

路线:

router.post("/login", async (req, res) => {
    const user = await User.findOne({ email: req.body.email });
    if (!user) res.send({ error: "User does not exists" });
    const validPass = await compare(req.body.password, user.password);
    if (!validPass) {
        return res.json({ error: "email or password is incorrect" });
    }

    
    const token = sign(
        { _id: user._id, isAdmin: user.isAdmin },
        process.env.SECRET,
        {
            expiresIn: "24h",
        },
    );
    res.header("auth-token", token).send({
        token,
        email: req.body.email,
        id: user._id,
    });

    
});


router.get("/adminPanel", isAdmin, isAuth, (req, res) => {
    res.json({
        title: "ADMIN PANEL",
    });
});

【问题讨论】:

  • 那么究竟是什么没有按预期工作?
  • @rveerd 识别管理员
  • 您不需要同时使用isAdminisAuth 中间件。实际上 isAuth 就足够了,因为您可以在 isAuth 中间件中检查用户是否是管理员,令牌具有信息。所以尝试从路由中删除 isAdmin 并在 isAuth 中尝试 console.log('Am i admin? :', verify.isAdmin);
  • 另外,这个let user = await userModel.findOne({ isAdmin }); 不太可能按照您想要的方式工作。这个{ isAdmin }{ isAdmin: isAdmin } 的快捷方式,这里的问题是isAdmin 是一个函数const isAdmin = async (req, res, next) => { 你的意思是使用{ isAdmin: verified.isAdmin } 吗?尽管即使这样也行不通,因为您只会找到第一个管理员用户,不一定是您认为的用户。你应该使用 _id 来代替 let user = await userModel.findOneById(verified._id); 但是我说你根本不需要 isAdmin 中间件。

标签: javascript node.js express jwt


【解决方案1】:

基于我的 cmets 的代码如下您的问题

const { verify } = require("jsonwebtoken");
const userModel = require("../model/userModel");

const isAuth = (req, res, next) => {
    const token = req.header("auth-token");
    if (!token) return res.status(401).send("Access denied");

    try {
        const verified = verify(token, process.env.SECRET);
        req.user = verified;
        console.log('Am i admin?', req.user.isAdmin);
        next();
    } catch (err) {
        res.status(400).send("Invalid token");
    }
};

const isAdmin = async (req, res, next) => {

    // no need to verify token again
    // the `req.user.isAdmin` is already available from isAuth
    // also no need to query a database, we have all the info we need from the token
    if (!req.user.isAdmin)
        return res.status(401).send({ msg: "Not an admin, sorry" });

    next();
};

router.post("/login", async (req, res) => {
    const user = findUserSomehow();
    
    const token = sign({ _id: user._id, isAdmin: user.isAdmin }, process.env.SECRET, { expiresIn: "24h" });

    res.header("auth-token", token).send({
        token,
        email: req.body.email,
        id: user._id,
    });    
});

// notice the order of middlewares, isAuth first
router.get("/adminPanel", isAuth, isAdmin, (req, res) => {
    res.json({
        title: "ADMIN PANEL",
    });
});

【讨论】:

  • 非常感谢。还有一个问题,我将如何注销用户?通过使用 auth-token 删除标头?
  • 不客气。我对 jwt 令牌不是很熟悉,所以很难说。但这肯定是一种方法。这取决于您在客户端存储 jwt 令牌的位置/方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
  • 2014-05-01
  • 2011-10-02
  • 2022-10-02
  • 1970-01-01
相关资源
最近更新 更多