Express + PassportJS 无法读取闪信

Express + PassportJS can't read flash messages

我有我的 Express + Passport + Firebase 项目,我在其中使用本地策略处理身份验证。因为我发现 Passport 会处理身份验证过程,所以我还发现它会接受 flash 消息作为 done() 函数(在策略中)的第三个参数。但我不确定如何阅读它们:

我猜我设置和读取即显消息的流程是:

  1. 使用 NPM 安装 connect-flash

  2. 导入后设置Express中间件:

import * as flash from 'connect-flash';
...
const app = express();
...
app.use(flash());
  1. 根据 documentation:
  2. 在 Express 路由中配置 Passport 身份验证
// POST - /api/v1/admin/oauth/login
router.post(
    '/login',
    async (req: Request, res: Response) => { /* middleware function to validate input */ },
    passport.authenticate('local', {
        failureRedirect: '/api/v1/admin/oauth/login',
        failureFlash: true
    }),
    async (req: Request, res: Response) => { /* function after success login */
);
  1. 根据 Passport configuration documentation:
  2. done() 方法中包含 flash 消息
import { Strategy as LocalStrategy } from 'passport-local';
import db from '../../config/database';
import * as bcrypt from 'bcryptjs';

export default new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => {
    const ref = db.collection('users').doc(email);
    try {
        const doc = await ref.get();
        if (!doc.exists) {
            return done(null, false, { error: 'Wrong email' });
        }

        const user = doc.data();

        const match: boolean = await bcrypt.compare(password, user.password);
        if (!match) {
            return done(null, false, { error: 'Wrong password' });
        }

        user.id = doc.id;
        delete user.password;

        return done(null, user);

    } catch(error) {
        return done(error);
    }
});
  1. 使用req.flash('error')读取即显消息:
// GET - /api/v1/admin/oauth/login
router.get('/login', (req: any, res: Response) => {
    const result: IResult = {
        message: '',
        data: null,
        ok: false
    };
    if (req.flash('error')) {
        resultado.message = req.flash('error');
        console.log(req.flash('error'));
    }
    return res.status(400).json(result);
});

我认为它在我的脑海中发挥了巨大的作用,直到第 5 步,其中 req.flash('error') 中有一个空数组。我做错了什么?

您传递的即显信息有误!

done() 的第三个参数应该是具有字段 typemessage:

的对象
return done(null, false, { message: 'Wrong email' });

类型默认为error

这个 API 似乎没有明确记录,但显示在 [=29= 的 配置 章节的 3rd example of the Verify Callback section 中] 文档。

我创建了 a repo,其中包含一个可重现性最低的工作示例。

我一直在搜索并找到了解决方案,但它在第二次登录尝试中有效。

我修改问题的步骤以使其有效:

  1. 使用 NPM 安装 connect-flash

  2. 导入后设置Express中间件:

import * as flash from 'connect-flash';
...
const app = express();
...
app.use(flash());
  1. 根据 documentation:
  2. 在 Express 路由中配置 Passport 身份验证
// POST - /api/v1/admin/oauth/login
router.post(
    '/login',
    async (req: Request, res: Response) => { /* middleware function to validate input */ },
    passport.authenticate('local', { 
        failureFlash: true,
        failureRedirect: '/api/v1/admin/oauth/login' 
    }),
    async (req: Request, res: Response) => { /* function after success login */
);
  1. 创建另一个路由,以便它可以显示 flash 消息,感谢@Codebling:
// GET - /api/v1/admin/oauth/login
router.get('/login', (req: Request, res: Response) => {
    const result: IResult = {
        message: 'Auth ok',
        data: null,
        ok: true
    };

    let status: number = 200;
    const flashMessage: any = req.flash('error');

    if (flashMessage.length) {
        resultado.message = flashMessage[0];
        resultado.ok = false;
        status = 400; 
    }

    return res.status(status).json(result);
});
  1. 根据 Passport configuration documentation:
  2. done() 方法中包含 flash 消息
import { Strategy as LocalStrategy } from 'passport-local';
import db from '../../config/database';
import * as bcrypt from 'bcryptjs';

export default new LocalStrategy({ usernameField: 'email' }, async (email, password, done) => {
    const ref = db.collection('users').doc(email);
    try {
        const doc = await ref.get();
        if (!doc.exists) {
            return done(null, false, { message: 'Wrong email' });
        }

        const user = doc.data();

        const match: boolean = await bcrypt.compare(password, user.password);
        if (!match) {
            return done(null, false, { message: 'Wrong password' });
        }

        user.id = doc.id;
        delete user.password;

        return done(null, user);

    } catch(error) {
        return done(error);
    }
});