在实现基于角色的身份验证时遇到Deliver.js和Passport.js问题.尽管设置了特定于角色的中间件,但我仍面临"太多重定向"错误.该应用程序涉及根据用户的角色将用户重定向到各自的仪表板(例如,管理员、招聘人员).如何解决此重定向循环并确保正确的身份验证流程?

我try 过的事情:我使用Passport.js在我的Deliver.js应用程序中实现了基于角色的身份验证.我定义了中间件功能来判断用户是否经过身份验证,并根据他们的角色(招聘人员、用户或管理员)将他们重定向到各自的仪表板.我还配置了Passport.js,以根据登录期间的角色对用户进行身份验证.

帖子主题:Re:Колибри

const LocalStrategy = require("passport-local").Strategy;
const db = require("./db");
const bCrypt = require("bcrypt");

async function initializePassport(passport) {
  async function authUser(email, password, formUserType, done) {
    try {
      let userType;
      switch (formUserType) {
        case "recruteur":
          userType = "recruteur";
          break;
        case "users":
          userType = "users";
          break;
        case "admin":
          userType = "admin";
          break;
        default:
          throw new Error("this user type does not exist");
      }

      const query = `SELECT * FROM ${userType} WHERE email = $1`;
      const { rows } = await db.query(query, [email]);
      const user = rows[0];

      if (!user) {
        return done(null, false, { message: "Incorrect email address" });
      }

      const passwordMatched = await bCrypt.compare(password, user.mot_de_passe);
      if (!passwordMatched) {
        return done(null, false, { message: "Incorrect password" });
      }

      user.userType = userType;
      return done(null, user, userType);
    } catch (error) {
      done(error);
    }
  }

  passport.use(
    new LocalStrategy(
      {
        usernameField: "email",
        passReqToCallback: true,
      },
      async (req, email, password, done) => {
        await authUser(email, password, req.body.userType, done);
      }
    )
  );

  passport.serializeUser((user, done) => {
    let userId;
    let userType;
    switch (user.userType) {
      case "recruteur":
        userId = user.recruteur_id;
        userType = "recruteur";
        break;
      case "users":
        userId = user.users_id;
        userType = "users";
        break;
      case "admin":
        userId = user.admin_id;
        userType = "admin";
        break;
      default:
        return done(new Error("Unknown user type"));
    }

   
    
    done(null, { id: userId, type: userType });
  });

  passport.deserializeUser(async (idObj, done) => {
    try {
      const { id, type } = idObj;
      let userType;
      switch (type) {
        case "recruteur":
          userType = "recruteur";
          break;
        case "users":
          userType = "users";
          break;
        case "admin":
          userType = "admin";
          break;
        default:
          return done(new Error("Unknown user type"));
      }
  
      const query = `SELECT * FROM ${userType} WHERE ${userType}_id = $1`;
      const { rows } = await db.query(query, [id]);
      const user = rows[0];
  
      if (!user) {
        return done(new Error("User not found"));
      }

      user.userType = userType;
      return done(null, user, userType);
    } catch (err) {
      done(err);
    }
  });
  
}

module.exports = initializePassport;

带有我的中间件的app.js文件checkAuthenticaded、checkNotAuthenticated

if (process.env.NODE_ENV !== "production") {
  require("dotenv").config();
}
const initializePassport = require("./config/passport.config");

const express = require("express");
const passport = require("passport");
const session = require("express-session");

const path = require("path");
const helmet = require("helmet");
const flash = require("express-flash");
const methodOverride = require('method-override');


const logger = require("morgan");

const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(flash());

//initialise user session
app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: true,
    cookie: {
      maxAge: 3 * 60 * 60 * 1000,
      httpOnly: true 
    }
  })
);

app.use(passport.session() );
app.use(passport.initialize());


app.use(methodOverride('_method'))

//auth the user in the DB
initializePassport(passport);

const checkAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    const userType = req.user.userType;
    console.log('Role --------------------------------------------------->',userType);
    if (userType === 'recruteur') {
      return res.redirect("/recruter/dashboard");
    } else if (userType === 'users') {
      return res.redirect("/users/dashboard");
    } else if (userType === 'admin') {
      return res.redirect("/admin/dashboard");
    } else {
      return res.redirect("/login");
    }
  } else {
    return res.redirect("/login");
  }
};





const checkNotAuthenticated = (req, res, next) => {
  if (!req.isAuthenticated()) {
    return next(); 
  } else {
    const userType = req.user.userType;
    switch (userType) {
      case 'recruteur':
        return res.redirect("/recruter/dashboard");
      case 'users':
        return res.redirect("/users/dashboard");
      case 'admin':
        return res.redirect("/admin/dashboard");
      default:
        return res.redirect("/login");
    }
  }
};

const staticFilesPath = path.join(__dirname, 'views');

app.use(helmet());
app.use(express.json());

app.use(express.static(path.join(__dirname, "views")));
app.use("views", express.static(path.join(__dirname, "views", "public")));
app.use(express.static(staticFilesPath, { type: 'application/javascript' }));


app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));

app.use(logger("tiny"));

module.exports = { app, checkAuthenticated, checkNotAuthenticated };

Server.js文件:

if (process.env.NODE_ENV !== 'production') {
  require("dotenv").config();
}

const offersRoute = require("./routes/offers/offers.route");
const homeRouter = require('./routes/home/home.route');
const offerRoute = require('./routes/offers/offer.route');
const authRoute = require('./routes/auth/auth.route');
const recruterRoute = require('./routes/recruter/recruter.route');
const usersRoute = require('./routes/users/users.route');
const unauthorizedRoute = require('./routes/auth/unauthorized.route');

const http = require("http");


const { app } = require("./app");

const PORT = process.env.PORT;

const server = http.createServer(app);

app.use('/home', homeRouter); 
app.use("/offers", offersRoute);
app.use("/offer", offerRoute);
app.use("/login", authRoute);
app.use("/recruter", recruterRoute);
app.use('/users', usersRoute);
app.use('/unauthorized', unauthorizedRoute)

server.listen(PORT, () => {
  console.log(`You are listening to port ${PORT}...`);
});

发帖主题:Re:Колибри0.7.0

const express = require("express");
const passport = require("passport");
const flash = require("express-flash");

const authRoute = express.Router();
const {
  postNewRecruterAuth,
  validate,
  recruterAuthValidationRule,
  postNewUserAuth,
  userAuthValidationRule,
} = require("../../controllers/auth.controller");
const { checkAuthenticated, checkNotAuthenticated } = require("../../app");

//User render login routes
authRoute.get("/", (req, res) => {
  res.render("auth/users/login", {
    title: "Connectez vous.",
  });
});

//User register routes
authRoute.get("/register", (req, res) => {
  res.render("auth/users/register", {
    title: "Créer un compte utilisateur",
  });
});

//User authentification routes
authRoute.post(
  "/",
  passport.authenticate("local", {
    successRedirect: "/users/dashboard",
    failureRedirect: "/login",
    failureFlash: true,
  })
);


//user registration route
authRoute.post(
  "/register",
  userAuthValidationRule(),
  validate,
  postNewUserAuth
);




//Recruter Auth routes
authRoute.get("/recruter", checkNotAuthenticated, (req, res) => {
  //recruter login
  res.render("auth/recruter/recruter_login", {
    title: "Connectez vous en tant que recruteur.",
    messages: req.flash("error"),
  });
});

//recruter login route
authRoute.post(
  "/recruter",
  passport.authenticate("local", {
    successRedirect: "/recruter/dashboard",
    failureRedirect: "/login/recruter",
    failureFlash: true,
  })
);

authRoute.get("/recruter/register", checkNotAuthenticated, (req, res) => {
  //recruter register
  res.render("auth/recruter/recruter_register", {
    title: "Créer un compte recruteur",
  });
});

authRoute.post(
  "/recruter/register",
  recruterAuthValidationRule(),
  validate,
  postNewRecruterAuth
);

//Admin Auth routes

module.exports = authRoute;

目前,我正在我的Deliver.js应用程序中测试专门针对招聘人员的登录功能.然而,当招聘人员成功登录时,应用程序不会被重定向到招聘人员仪表板("/recruter/dashboard"),而是进入无限重定向循环.

我实际上正在测试的recruter.Route.js文件:

const express = require("express");
const recruterRoute = express.Router();
const passport = require("passport");
const { checkAuthenticated } = require("../../app");

recruterRoute.get("/", (req, res) => {
  res.render("layouts/recruter/recruter_page", {
    title: "Jobify pour recruteur",
  });
});

recruterRoute.post("/dashboard/logout", (req, res) => {
  req.logout(() => {
    res.redirect("/login/recruter");
  });
});

recruterRoute.get("/dashboard", checkAuthenticated,   (req, res) => {
  res.render("layouts/recruter/recruter_dashboard", {
    title: "Votre tableau de bord",
    user: req.user,
  });
});

module.exports = recruterRoute;

我的期望:我的期望是,当用户登录时,他们会根据其角色被重定向到适当的仪表板.例如,招聘人员应重定向到"/recruiter/dashboard",用户应重定向到"/users/dashboard",管理员应重定向到"/admin/dashboard".我还预计身份验证过程将无缝工作,无需任何重定向循环.

实际结果:但是,当我测试应用程序时,我遇到了"太多重定向"错误.似乎在身份验证过程中的某个地方发生了重定向循环,但我不确定问题出在哪里.尽管设置了角色特定的中间件并配置了Passport.js来处理基于角色的身份验证,重定向循环仍然存在,而且我无法解决它.

这是我在日志(log)中得到的无限循环:

GET /login/recruter 200 14109 - 9.306 ms
POST /login/recruter 302 82 - 104.179 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.246 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.197 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.033 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.213 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.997 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.092 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.248 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.335 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.232 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.296 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.186 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.198 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.775 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.093 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.145 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.099 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.038 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.684 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.291 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.575 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.015 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.837 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.956 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.713 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.973 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.684 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.953 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.527 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.906 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.907 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 0.629 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.024 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 3.310 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.657 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.030 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.575 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.036 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.140 ms
Role ---------------------------------------------------> recruteur
GET /recruter/dashboard 302 82 - 1.440 ms

推荐答案

问题在于,位于所有需要验证的路由处理程序前面的checkAuthenticated中间件从未调用next()来允许处理程序实际处理请求.相反,它总是执行重定向.

您似乎正在try 为访问控制实现角色.我建议像这样更改您的身份验证中间件:

const checkAuthenticated = (requiredRole) => (req, res, next) => {
  if (!req.isAuthenticated()) {
    return res.redirect("/login");
  }

  const userType = req.user.userType;
  if (userType !== requiredRole) {
    return redirectToRoleHomePage(req, res);
  }

  // user is authenticated and has the correct role,
  // pass control to the handler from this middleware
  return next();
};

const checkNotAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    return redirectToRoleHomePage(req, res);
  }

  // user is *not* authenticated, pass control to the handler
  return next();
};

const redirectToRoleHomePage = (req, res) => {
  const userType = req.user.userType;
  switch (userType) {
    case "recruteur":
      return res.redirect("/recruter/dashboard");
    case "users":
      return res.redirect("/users/dashboard");
    case "admin":
      return res.redirect("/admin/dashboard");
    default:
      return res.redirect("/login");
  }
};

现在,如果不满足条件,check*中间件就会重定向,否则就会调用next().我已将checkAuthenticated更改为requiredRole参数-这允许您在处理程序级别指定该处理程序需要哪个角色.通过此,您可以更改处理程序,如下所示:

recruterRoute.get("/", (req, res) => {
  res.render("layouts/recruter/recruter_page", {
    title: "Jobify pour recruteur",
  });
});

recruterRoute.post("/dashboard/logout", checkAuthenticated('recruteur'), (req, res) => {
  req.logout(() => {
    res.redirect("/login/recruter");
  });
});

recruterRoute.get("/dashboard", checkAuthenticated('recruteur'), (req, res) => {
  res.render("layouts/recruter/recruter_dashboard", {
    title: "Votre tableau de bord",
    user: req.user,
  });
});

对于其他角色,您可以使用checkAuthenticated('users')checkAuthenticated('admin')等.

或者,如果您希望recruterRoute中的all条路由来判断用户是否已登录并且是recruteur,则可以在recruterRoute Router本身中应用中间件,这样您就不需要记住每条路由的它了:

const recruterRoute = express.Router();

recruterRoute.use(checkAuthenticated('recruteur'));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// middleware applied with `.use()` before the routes
// -> gets called before any route below

recruterRoute.get("/", (req, res) => {
  res.render("layouts/recruter/recruter_page", {
    title: "Jobify pour recruteur",
  });
});

recruterRoute.post("/dashboard/logout", (req, res) => {
  req.logout(() => {
    res.redirect("/login/recruter");
  });
});

recruterRoute.get("/dashboard", (req, res) => {
  res.render("layouts/recruter/recruter_dashboard", {
    title: "Votre tableau de bord",
    user: req.user,
  });
});

Javascript相关问答推荐

为什么子组件没有在reaction中渲染?

添加/删除时React图像上传重新渲染上传的图像

JavaScript文本区域阻止KeyDown/KeyUp事件本身上的Alt GR +键组合

是什么原因导致此Angular 16电影应用程序中因类型错误而不存在属性?

通过嵌套模型对象进行Mongoose搜索

在Three JS中看不到补间不透明度更改效果

如何从网站www.example.com获取表与Cheerio谷歌应用程序脚本

如何避免页面第一次加载时由于CSS样式通过JavaScript更改而出现闪烁

优化Google Sheet脚本以将下拉菜单和公式添加到多行

如何在文本字段中输入变量?

JS:XML insertBefore插入元素

连接到游戏的玩家不会在浏览器在线游戏中呈现

类构造函数忽略Reaction Native中的可选字段,但在浏览器中按预期工作

为什么JPG图像不能在VITE中导入以进行react ?

如何限制显示在分页中的可见页面的数量

如何使用基于promise (非事件emits 器)的方法来传输数据?

Phaserjs-创建带有层纹理的精灵层以自定义外观

从逗号和破折号分隔的给定字符串中查找所有有效的星期几

如何使用<;Link>;执行与JS Reaction中的";window.Location=/GameOverDied;";类似的操作?

React:防止useContext重新渲染整个应用程序或在组件之间共享数据而不重新渲染所有组件