错误:req#logout需要一个回调函数。

49

我无法找到解决方法,尝试了一切,我是第一次使用护照。 错误:req#logout需要回调函数 我以前编写过这个,但那时没有收到任何错误,但这次不知道为什么会出现这种情况,我也阅读了护照文档并尝试了所有解决方案

提前致谢

<%- include('partials/header') %>

<header>
    <nav class="flex align-item-center">
        <div class="div-left">
            <img id="userimg" src="img/user.png" alt="logo">
        </div>
        <div class="div-right flex">
            <div style="font-size: 14px">
                <a href="/logout" role="button"> Logout</a>
            </div>
        </div>
    </nav>
</header>

<%- include('partials/footer') %>

JavaScript 代码

require('dotenv').config();
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require('express-session');
const passport = require('passport');
const passportLocalMongoose = require('passport-local-mongoose');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const findOrCreate = require('mongoose-findorcreate');

const app = express();

app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
    extended: true
}));

app.use(session({
    secret: process.env.SECRET,
    resave: false,
    saveUninitialized: false
}))

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

mongoose.connect("#DB")

const accountsdata = new mongoose.Schema({
    email: String,
    password: String,
    googleId: String,
    facebookId: String,
    combo: String,
    date: String,
    price: String,
    accountemail: String

});

accountsdata.plugin(passportLocalMongoose);
accountsdata.plugin(findOrCreate);

const data = new mongoose.model("amazonprime", accountsdata);

passport.use(data.createStrategy());

passport.serializeUser(function (user, cb) {
    process.nextTick(function () {
        cb(null, { id: user.id, username: user.username });
    });
});

passport.deserializeUser(function (user, cb) {
    process.nextTick(function () {
        return cb(null, user);
    });
});

passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "http://localhost:3000/auth/google/home",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
    function (accessToken, refreshToken, profile, cb) {
        console.log(profile)
        data.findOrCreate({ googleId: profile.id }, function (err, user) {
            return cb(err, user);
        });
    }
));

app.get("/", (req, res) => {
    res.render("login");
});

app.get('/auth/google',
    passport.authenticate("google", { scope: ["profile"] })
);

app.get("/auth/google/home",
    passport.authenticate("google", { failureRedirect: "/" }),
    function (req, res) {

        res.redirect("/home");
    });

app.get("/signup", (req, res) => {
    res.render("signup");
});

app.get("/home", function (req, res) {
    if (req.isAuthenticated()) {
        res.render("home");

    } else {
        res.redirect("/");
    }
})

app.get("/logout", (req, res) => {
    req.logout();
    res.redirect("/");
});


app.post("/signup", (req, res) => {

    data.register({ username: req.body.username }, req.body.password, function (err, user) {
        if (err) {
            console.log(err);
            res.redirect("/signup");
        } else {
            passport.authenticate("local")(req, res, function () {
                res.redirect("/home");
            })
        }
    })
})

app.post("/", function (req, res) {

    const user = new data({
        username: req.body.username,
        password: req.body.password
    })
    req.login(user, function (err) {
        if (err) {
            console.log(err);
        } else {
            passport.authenticate("local")(req, res, function () {
                res.redirect("/home")
            })
        }
    })
});

app.get("/logout", (req, res) => {
    req.logout();
    res.redirect("/");
});




app.listen(3000, function () {
    console.log("Server started on port 3000.");
});

错误

Error: req#logout requires a callback function
    at IncomingMessage.req.logout.req.logOut (E:\Web Development\Data Handler\node_modules\passport\lib\http\request.js:65:44)
    at E:\Web Development\Data Handler\app.js:105:9
    at Layer.handle [as handle_request] (E:\Web Development\Data Handler\node_modules\express\lib\router\layer.js:95:5)
    at next (E:\Web Development\Data Handler\node_modules\express\lib\router\route.js:144:13)
    at Route.dispatch (E:\Web Development\Data Handler\node_modules\express\lib\router\route.js:114:3)
    at Layer.handle [as handle_request] (E:\Web Development\Data Handler\node_modules\express\lib\router\layer.js:95:5)
    at E:\Web Development\Data Handler\node_modules\express\lib\router\index.js:284:15
    at Function.process_params (E:\Web Development\Data Handler\node_modules\express\lib\router\index.js:346:12)
    at next (E:\Web Development\Data Handler\node_modules\express\lib\router\index.js:280:10)
    at SessionStrategy.strategy.pass (E:\Web Development\Data Handler\node_modules\passport\lib\middleware\authenticate.js:346:9)

请检查一下我是否已经添加了错误堆栈。 - Harsh Gupta
10个回答

112

自从0.6.0版本(在撰写本文时仅几天前发布)起,req.logout已经变成了异步操作。这是一项更大的变化的一部分,旨在避免会话固定攻击。

请参见发布公告

The other major change is that that req.logout() is now an asynchronous function, whereas previously it was synchronous. For instance, a logout route that was previously:

app.post('/logout', function(req, res, next) {
  req.logout();
  res.redirect('/');
});

should be modified to:

app.post('/logout', function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect('/');
  });
});

Jared Hanson 提到文档还没有更新:

为了提高注销期间会话管理的安全性,这是必要的。升级到0.6.0将需要应用程序传递一个回调函数给req#logout。我仍在更新文档和示例。


1
那么 express-sessionlogout 逻辑中不需要 req.session.destroy() 吗? - Daniel
感谢您提供简单明了的解释。我正在Udemy上跟随Colt Steele的Web Developer Bootcamp 2023(具体来说是第51节),这是在变更发生之前创建的,因此视频中没有提到。这个解决方案为我减轻了很多压力。谢谢! - CSG
@HarshGupta:感谢您提出修改建议,但这并没有意义。1)这是链接发布说明文章的引用,它使用POST,因此在此处编写GET是不正确的。2)应该是POST而不是GET,因为注销会更改状态,而GET不允许更改状态,它只能读取状态。 - CherryDT

7

我也是学习者,曾经遇到同样的问题。当时我一直在尝试,直到讲师提到req.login()需要一个回调函数。他使用了一个错误处理函数作为回调,结果在req.logout()时也表现良好。

或许你可以尝试这个方法:

app.get("/logout", (req, res) => {
  req.logout(req.user, err => {
    if(err) return next(err);
    res.redirect("/");
  });
});

4

I have found this code in official passportjs and it worked for me I hope it will resolve your problem as well Passport exposes a logout() function on req

app.get('/logout', function(req, res, next){
    req.logout(function(err) {
      if (err) { return next(err); }
      res.redirect('/');
    });
  });


这在我今天起作用。谢谢文档链接。文档链接建议使用POST或DELETE,但对我都不起作用。所以像你发布的那样使用GET,它有效。 - Guzumba

2
如果您正在跟随Angela Yu的Web开发训练营,请使用以下内容:
app.get('/logout', function(req, res, next) {
  req.logout(function(err) {
    if (err) { 
      return next(err); 
      }
    res.redirect('/');
  });
});

我已经能够使用app.get使其工作,但passport文档说要使用post或delete来防止恶意攻击。我无法让app.post工作,我得到一个错误,说“无法获取/logout”。post真的必要吗?如果是这样,我该如何解决这个问题?我的app.post看起来像这样... req.logout(function(err) { if (err) { return next(err); } res.redirect('/'); }); });``` - tamio42

1

这对我来说完美地运作:

app.get("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect("/");
  });
});

你也可以使用这个:

app.post("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) { return next(err); }
    res.redirect("/");
  });
});

两者都可以,干杯!!!


1

0
app.get('/users/logout', (req, res, next) => {
  req.logout(function (err) {
    if (err) {
      return next(err);
    }
    // if you're using express-flash
    req.flash('success_msg', 'session terminated');
    res.redirect('/login');
  });
});

请阅读如何撰写优质回答?。尽管这段代码块可以回答提问者的问题,但如果您能解释一下这段代码与原问题中的代码有什么不同,您所做的更改是什么,为什么要做出这些更改以及为什么这样做可以解决问题而不会引入其他问题,那么您的回答将会更加有用。 - Saeed Zhiany

0

这是我的问题,它无法正常工作:

app.get("/logout", (req, res) => {
  req.logout();
  res.redirect("/");
});

答案是:

require("dotenv").config();

const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const session = require("express-session");
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");

const app = express();
app.use(express.static("public"));

app.use(bodyParser.urlencoded({
  extended: true
}));

app.set("view engine", "ejs");

app.use(
  session({
    secret: "our little secret.",
    resave: false,
    saveUninitialized: false,
  })
);

app.use(passport.initialize());

app.use(passport.session());

mongoose.connect("mongodb://127.0.0.1/userDB");

const userSchema = new mongoose.Schema({
  email: String,
  password: String,
});

userSchema.plugin(passportLocalMongoose);

const User = new mongoose.model("User", userSchema);

passport.use(User.createStrategy());

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());

app.get("/", (req, res) => {
  res.render("home");
});

app.get("/login", (req, res) => {
  res.render("login");
});

app.get("/register", (req, res) => {
  res.render("register");
});

app.get("/secrets", (req, res) => {
  if (req.isAuthenticated()) {
    res.render("secrets");
  } else {
    res.redirect("/login");
  }
});

app.get("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) {
      return next(err);
    }
    res.redirect("/");
  });
});

0
<nav class="grey darken-3">
  <div class="nav-wrapper container">
    <a href="#!" class="brand-logo center">StoryBooks</a>
    <a href="#" data-target="mobile-demo" class="sidenav-trigger show-on-large"><i class="fas fa-bars"></i></a>
    <ul class="sidenav" id="mobile-demo">
      <li><a href="/stories">Public Stories</a></li>
      <li><a href="/dashboard">Dashboard</a></li>
      <li><a href="/auth/logout">Logout</a></li>
    </ul>
  </div>
</nav>

重要的是不仅要发布代码,还要包括代码的描述以及为什么建议使用它。这有助于他人理解代码的上下文和目的,并使其对阅读问题或答案的其他人更有用。 - DSDmark

0
app.get("/logout", function(req, res, next) {
  req.logout(function(err) {
    if (err) {
      return next(err);
    }
    res.redirect("/");
  });
});

这对我来说很有效!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接