Node.js 根据注册中的用户角色切换配置文件路由(Express.js)

Node.js 根据注册中的用户角色切换配置文件路由(Express.js),node.js,express,middleware,mern,express-router,Node.js,Express,Middleware,Mern,Express Router,读得有点长 我目前正在为一个MERN项目构建后端,其结构非常有趣(我将更改细节,因为它是一个私有项目) 数据库:目前有4个数据库模式,1个用户模式有3个不同的角色:学生、教师和赞助者 **这三种类型的用户角色都有自己独特但非常相似的配置文件模式(TeacherProfile、StudentProfile e.t.c),它们都通过ID**引用用户shcema const mongoose = require('mongoose'); const studentProfileSchema =

读得有点长

我目前正在为一个MERN项目构建后端,其结构非常有趣(我将更改细节,因为它是一个私有项目)

  • 数据库:目前有4个数据库模式,1个用户模式有3个不同的角色:学生、教师和赞助者
**这三种类型的用户角色都有自己独特但非常相似的配置文件模式(TeacherProfile、StudentProfile e.t.c),它们都通过ID**引用用户shcema

const mongoose = require('mongoose');

const studentProfileSchema = new mongoose.Schema({
   user: {
       // create a reference to the user schema
       type: mongoose.Schema.Types.ObjectId,
       ref: 'user'
   },.........
  • 我有一个负责jwt逻辑的认证中间件
现在路线上的事情变得有趣了

  • 我有一个用户路径,负责用户注册

  • 用于登录和身份验证的身份验证路由

  • 和3条路线的配置文件

我想要构建的是一个中间件逻辑,一旦用户注册,它将在3个项目路由之间切换,这样他/她将在注册期间返回描述choosen角色的概要文件

请记住,有对数据库的调用,我必须将其包装在异步块中

这是此类路线之一的示例:

const express = require('express');
const router = express.Router();
const config = require('config');
// validator
const {check, validationResult} = require('express-validator');
// auth middleware
const auth = require('../../middleware/authMiddleware');

// db collections
const SponsorProfile = require('../../models/SponsorProfile');
const User = require('../../models/User');

// @route   GET api/SponsorProfile/me
// @desc    GET current user profile
// @access  Private 
router.get('/me', auth, async (req, res) => {
   try {
       // fetch profile object
       const sponsorProfile = await SponsorProfile.findOne({user:req.user.id});
       // check if profile exists
       if(!sponsorProfile) {
           return res.status(400).json({msg: 'Hello Sponsor, You have not created a profile'})
       }
       res.json(sponsorProfile)
   } catch (error) {
       console.error(error.message);
       res.status(500).json({msg:'This is our fault not yours'})
   }
})


module.exports= router;
现在我试着这么做:

  • 我构建了一个主路由器,它使用所有的配置文件路由器作为从学生到赞助商的子路由器
  • 然后在server.js中调用它,如下所示:
  • 方法是在前两个路由器中放置一个中间件函数,并将第三个路由器保留为空,这样,如果前两个路由器中的标准通过,将有一个交换机
显然这不起作用

  • 然后我尝试了这样的中间件功能
不行

那么这个,

    async function shouldRouterChange(req, res, next) {

        try {
            let userRole = await studentProfile.findOne({user:req.user.id}).populate('user', ['role']);
            // conditional
           console.log(userRole)
            if (userRole.role==='mentor') {
                return next('router')
           }
             return next()
        } catch (error) {
            console.error(error.message)
            res.status(500).json({msg: 'Server Error'})
        }
        
    } 
我尽可能地进行了调试,并意识到:

  • 整个交换结构实际上工作得很好
  • 问题在于中间件结构
  • 第一个中间件结构可能是corerct,而不是条件结构
  • 条件等同于null或未定义(它不能正确获取用户角色)
  • 整个中间件逻辑可能必须在返回概要文件的
    router.get()逻辑中调用

  • 我的问题是如何使条件正确,从而使中间件结构正常工作(可能不会对我的应用程序结构做太多更改,无论如何都不会介意)

    我已经解决了错误,它工作起来很有魅力

    使用路由器级中间件交换路由器(也可以交换单路由)

  • 为所有这些路由器(现在是子路由器)构建主路由器:
  • 将主路由器路径添加到server.js:

    应用程序使用('/api/profileRouter',要求('/routes/api/profileRouter')

  • 构建中间件逻辑,有条件地切换路由器:

  • 从学生路由器文件切换到教师路由器文件的中间件:

    我们的逻辑是根据用户在注册时选择的角色进行切换。这意味着角色是用户模式中的DB字段。 我们所要做的就是在身份验证负载中添加角色。 在用户注册时创建一个令牌,该令牌使用用户id作为有效负载,因此如果我们将角色添加到该有效负载,我们现在可以在“req”对象中访问它,并围绕它构建我们的条件

    此有效负载使用auth中间件位于我的auth路由中:

    此外,中间件功能中的“下一个(路由器)”是切换到profilesRouter中路由器堆栈中的下一个路由器的魔法。 它启动一个开关,然后在我们最后返回下一个时调用该开关

     return next().
    
  • 调用第一个子路由器(学生路由器)中的teacherSwitch中间件
  • 创建另一个中间件,有条件地切换到第三个子路由器
  • 6在第二个子路由器中调用它

    router.get('/me', [auth, partnerSwitch], async (req, res) => ...
    
    也就是说,只要不满足条件,它就会不断切换,直到条件通过为止。 其工作原理与常规switch语句类似

    这里我缺少的是,为了能够使用角色进行切换,我必须将其作为auth负载的一部分调用,这样它就成为req、res循环中请求对象的一部分,因此可以根据需要进行操作

    我们永远不需要在最后一个路由器中调用另一个中间件,因为从逻辑上讲,只有当一切都失败时,交换才会到达那里,就像常规switch语句中的默认值一样

    得到了我的一些帮助

    一个用户使用它来手动解码我的JWT令牌,以准确地知道发生了什么

        async function shouldRouterChange(req, res, next) {
            let userRole = await User.findOne({user:req.role}).select('-password');
            console.log(userRole)
            if ( userRole === 'mentor') {
         return next('router');
            }
            return next();
        }
         function shouldRouterChange(req, res, next) {
            if (req.user.role === 'teacher') {
                return next('router');
            }
            return next();
        }
    
    // @route   GET api/studentProfile/me
    // @desc    GET current user profile
    // @access  Private 
    router.get('/me', [auth, shouldRouterChange], async (req, res) => {
        try {
            // check if profile exists
            const studentProfile = await StudentProfile.findOne({user:req.user.id}).populate('user', ['role']);
            if(!studentProfile) {
                return res.status(400).json({msg: 'Hello student, You have not created a profile'})
            }
            res.json(studentProfile)
        } catch (error) {
            console.error(error.message);
            res.status(500).json({msg:'This is our fault not yours'})
        }
    })
    
    module.exports= router;
    
        async function shouldRouterChange(req, res, next) {
            let userRole = await User.findOne({user:req.role}).select('-password');
            console.log(userRole)
            if ( userRole === 'mentor') {
         return next('router');
            }
            return next();
        }
    
        async function shouldRouterChange(req, res, next) {
    
            try {
                let userRole = await studentProfile.findOne({user:req.user.id}).populate('user', ['role']);
                // conditional
               console.log(userRole)
                if (userRole.role==='mentor') {
                    return next('router')
               }
                 return next()
            } catch (error) {
                console.error(error.message)
                res.status(500).json({msg: 'Server Error'})
            }
            
        } 
    
    const express = require('express');
    const profilesRouter = express.Router();
    
    profilesRouter.use('/', require('./studentProfile'));
    profilesRouter.use('/', require('./teacherProfile'));
    profilesRouter.use('/', require('./sponsorProfile'));
    
    module.exports = profilesRouter;
    
    const jwt = require('jsonwebtoken');
    const config = require('config');
    
    // Check user profile
    function teacherSwitch(req, res, next) {
      const token = req.header('x-auth-token');
    
      //  if no token is returned
      if (!token) {
        return res.status(401).json({ msg: 'No token, permission denied' });
      }
    
      try {
        // decode token
        const decoded = jwt.verify(token, config.get('jwtSecret'));
        // set role to the same value as in the request
        req.user.role = decoded.user.role;
        // check if role is teacher
        if (decoded.user.role !== 'student') {
          return next('router');
        }
        return next();
      } catch (error) {
        res.status(401).json({ msg: 'Wrong token, authentication failed' });
      }
    }
    
    module.exports = teacherSwitch;
    
    
       // create jwt payload
        const payload = await {
    
          user: {
            id: user.id,
            role: user.role,
          },
        };
        // if user login is successful, return token
        jwt.sign(payload, config.get('jwtSecret'),
          { expiresIn: 36000 }, (error, token) => {
            if (error) throw error;
            return res.json({ token });
          });
      } catch (error) {
        console.error(error.message);
        res.status(500).send('Server Error');
      }
    
     return next().
    
    router.get('/me', [auth, teacherSwitch], async (req, res) => {
      try {
        // check if profile exists
        const studentProfile = await StudentProfile.findOne({ user: req.user.id });
        if (!teacherProfile) {
          return res.status(400).json({ msg: 'Hello student, You have not created a profile' });
        }
        return res.json(studentProfile);
      } catch (error) {
        console.error(error.message);
        return res.status(500).json({ msg: 'This is our fault not yours' });
      }
    });
    
    function sponsorSwitch(req, res, next) {
        const token = req.header('x-auth-token');
      
        //  if no token is returned
        if (!token) {
          return res.status(401).json({ msg: 'No token, permission denied' });
        }
      
        try {
          // decode token
          const decoded = jwt.verify(token, config.get('jwtSecret'));
          // set role to the same value as in the request
          req.user.role = decoded.user.role;
          // check if role is partner
          if (decoded.user.role !== 'teacher') {
            return next('router');
          }
          return next();
        } catch (error) {
          res.status(401).json({ msg: 'Wrong token, authentication failed' });
        }
      }
    
    router.get('/me', [auth, partnerSwitch], async (req, res) => ...