为啥我在使用 Passport 和会话时没有保持登录状态? Passport 的“isAuthenticated()”总是返回 false

Posted

技术标签:

【中文标题】为啥我在使用 Passport 和会话时没有保持登录状态? Passport 的“isAuthenticated()”总是返回 false【英文标题】:Why I'm not kept logged in when using Passport and sessions? Passport's "isAuthenticated()" always returns false为什么我在使用 Passport 和会话时没有保持登录状态? Passport 的“isAuthenticated()”总是返回 false 【发布时间】:2021-11-06 02:58:08 【问题描述】:

我正在使用 Angular、Passport 和会话进行身份验证。我可以创建一个新用户,登录但是,

问题

当检查用户是否使用 Passport 的 isAuthenticated() 函数登录时,总是返回 false。我按照各种在线资源的说明进行操作,但不确定是否:

问题

我可以在我的 Angular 应用中使用护照和会话吗?或者我只是在我的代码中做错了什么?如果你们有任何想法/提示为什么它不起作用,我将不胜感激。谢谢。

后端代码

const cors = require('cors');
const express = require("express");
const app = express();
const PORT = 3000;
const mongoose = require('mongoose');
const seedDB = require("./helpers/dbseed");

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

// the model with Passport-Local Mongoose plugged in
const User = require("./models/user");
const Profile = require("./models/profile");
const Recipe = require('./models/recipe');
const Macro = require ("./models/macro");
const Micro = require ("./models/micro");
const Ingredient = require("./models/ingredient");

// const isLoggedIn = require("./middleware/auth");

mongoose.connect('mongodb://localhost:27017/foodAppCopy', useNewUrlParser: true, useUnifiedTopology: true)
    .then(() => 
        console.log("Mongo Connection open");
    )
    .catch((error) => 
        console.log("No, Mongo -> Connection Error " + error);
    )

seedDB();

app.use(express.urlencoded( extended: true ));

app.use(cors());
app.options('*', cors());
app.use(express.json());

const sessionConfig = 
    secret: 'pass',
    resave: false,
    saveUninitialized: true,
    cookie: 
        httpOnly: true,
        expires: Date.now() + 1000 * 60 * 60 * 24 * 7,
        maxAge: 1000 * 60 * 60 * 24 * 7,
    

app.use(session(sessionConfig));

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

// passport.use(new LocalStrategy(User.authenticate()));

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

// Create New User
app.post('/register', async (req, res) => 
    try 
        const name, email, password = req.body;
        const user = new User(name, email);
        const registeredUser = await User.register(user, password);
        // This is used to create a profile
        res.send(registeredUser._id);
     catch(e) 
        console.log(e.message);
    
);

// Login
app.post('/login', passport.authenticate('local', successRedirect: '/recipes'), 
    async(req, res) => 
);

// Create Profile
app.post('/profile', async(req, res) => 
    const userID, profileData = req.body;
    let user = await User.findOne(_id: userID);
    if (user === null || user.length <= 0) 
        return res.status(422).json("Could not create profile");
     else 
        let newProfile = new Profile(
            userID: user._id,
            dob: profileData.dob,
            gender:profileData.gender,
            weightGoal:profileData.weightGoal,
            weeklyLossFrequency:profileData.weeklyLossFrequency,
        )
        await newProfile.save();
    
);

// INDEX Recipes
app.get('/recipes', async (req, res) => 
    if(!req.isAuthenticated()) 
        console.log("error");
        return res.status(422).json("You need to be logged in");
    
    const recipes = await Recipe.find();
    res.send(recipes);
);

中间件文件

    module.exports.isLoggedIn = (req, res, next) => 
        if(req.isAuthenticated()) 
            return next()
         
        res.status(403).send("Please login");
     


  [1]: https://i.stack.imgur.com/GsfG8.png

用户模型

const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");

const UserSchema = new mongoose.Schema(
    email: 
        type: String, 
        required: true,
    ,
)

UserSchema.plugin(passportLocalMongoose, 
    usernameField: "email"
);

module.exports = mongoose.model("User",UserSchema);

控制台出错

【问题讨论】:

能否也显示用户模型文件?因为这显然是大多数身份验证工作发生的地方。 当然,很抱歉。我现在才加的。 您的代码看起来不完整。我正在看这个app.post('/login', passport.authenticate('local', successRedirect: '/recipes', failureRedirect: "/login"), async(req, res) =&gt; ),我可以看到异步函数没有完成。 另外你的用户模式是错误的,你只添加了电子邮件,你也需要密码。你的代码有很多问题。你能告诉我你正在寻找的示例/教程的链接吗?我怀疑这是因为您没有在任何地方设置不记名令牌,或者您的用户注册完全错误。 我正在查看示例,但很难将其与您的代码进行比较,因为您只共享了其中的一部分。如果您的问题尚未解决,请随时与我们聊天。 【参考方案1】:

我只是猜测出了什么问题,因为您没有在问题中准确说明应用程序的端口,但我认为它是 4200,因为我看到您已将这些行添加到原始项目中:

app.use(cors());
app.options('*', cors());

您可能在遇到此类错误后添加了它们:

从源访问“http://localhost:3000/”获取 “http://localhost:4200”已被 CORS 策略阻止:否 请求中存在“Access-Control-Allow-Origin”标头 资源。

如果我的假设是正确的,那么您遇到的问题是另一个与运行在 3000 端口上的后端和在端口 4200 上运行的前端有关的问题。

确实,您正在使用会话并且您已将其配置为使用 cookie。但是,除非设置了一些特殊选项,否则不会从另一个域发送 cookie(不同的端口被视为不同的域):

HTTP 响应中的 access-control-allow-credentials: true 标头 HTTP 请求中的withCredentials 选项 SameSite=none cookie 属性

这些选项往往会降低您网站的安全级别(其他 CORS 选项也是如此)。保持良好安全级别并避免这些错误的最简单解决方案是在同一端口上为前端和后端提供服务。

在本地环境中,这可以通过Angular development proxy 来完成,您可以像这样配置:


  "/backend": 
    "target": "http://localhost:3000",
    "secure": false,
    "pathRewrite": 
      "^/backend": ""
    
  

不要忘记 angular.json 文件中对新文件的引用:

"proxyConfig": "src/proxy.conf.json"

之后,将所有后端调用从 http://localhost:3000/... 更改为 http://localhost:4200/backend/...,您的登录应该可以正常工作(您也可以删除两条 CORS 行)。

【讨论】:

哇,是的,你是对的!另外,我做了你推荐的所有更改,每个文档,在我的 angular.json 中,我添加了类似这样的选项 "options": "browserTarget": "food-app:build", "proxyConfig": "src/proxy.conf .json”。但是,现在当我第一次注册和登录消息时,我在控制台中收到这些错误:“localhost:4200/recipes 的 Http 失败响应:404”名称:“HttpErrorResponse”状态:404 url​​:“localhost:4200/recipes”和终端 [HPM]尝试将请求 /profile 从 localhost:4200 代理到 localhost:3000 时发生错误 你在最后一步忘记了一个细节:不要打电话给/recipes,而是/backend/recipes 明白了。也许我没有正确理解,但我替换了 Angular 中的每个后端调用。例如:食谱服务:public fetchRecipes() return this.http .get("localhost:4200/backend/recipes", ) .pipe( map((responseData) => let receivedDbRecipes: Recipe[] = [ ]; responseData.map((eachDbRecipe) => receivedDbRecipes.push(eachDbRecipe); ); return receivedDbRecipes; ), catchError((errorResponse) => return throwError(errorResponse); ) ); 是的,就是这样,您甚至可以在不指定主机名和端口的情况下编写相对 URL:/backend/recipes。这不行吗? 您在配置文件创建后忘记使用req.login。它也在您正在处理的初始代码中:github.com/Colt/YelpCamp/blob/…

以上是关于为啥我在使用 Passport 和会话时没有保持登录状态? Passport 的“isAuthenticated()”总是返回 false的主要内容,如果未能解决你的问题,请参考以下文章

没有会话的 Passport js 身份验证

生产环境会话对象中不存在 Passport 对象

如何在没有会话的情况下整合passport-facebook和jwt?

Alexa 会话保持打开状态,不会向用户提示。为啥认证反馈失败?

Passport.js 策略在不使用会话时失败

使用 websockets 和 Nest.js 的 Passport 会话身份验证未进行身份验证