Express + PassportJS 无法读取 flash 消息
Posted
技术标签:
【中文标题】Express + PassportJS 无法读取 flash 消息【英文标题】:Express + PassportJS can't read flash messages 【发布时间】:2020-07-18 14:18:49 【问题描述】:我有我的 Express + Passport + Firebase 项目,我在其中使用本地策略处理身份验证。由于我发现 Passport 会处理身份验证过程,所以我还发现它会接受 flash 消息作为 done()
函数的第三个参数(在策略中)。但我不确定如何阅读它们:
我想我设置和阅读 Flash 消息的流程是:
使用 NPM 安装 connect-flash。
导入后设置 Express 中间件:
import * as flash from 'connect-flash';
...
const app = express();
...
app.use(flash());
-
在 Express 路由中根据 documentation 配置 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 */
);
-
在
done()
方法中包含flash消息,根据Passport configuration documentation:
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);
);
-
使用
req.flash('error')
阅读flash消息:
// 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')
中有一个空数组。我做错了什么?
【问题讨论】:
Flash 消息仅在请求的生命周期内可用。向HTTP POST
发出/login
请求会获得使用权并闪烁一条消息,该消息可以适当地呈现以响应HTTP POST
请求。 HTTP GET
请求是一个单独的请求,不会在另一个 HTTP POST
请求中检索闪现的消息。
@OluwafemiSule 这不正确。 Flash 消息存储在会话中,可用于后续请求。
这是闪存消息的记录行为。那么文档肯定是错误的。
@OluwafemiSule 来源?文档显示“使用 Flash 消息需要 req.flash() 函数”。当使用connect-flash
提供req.flash()
功能时,根据问题,闪存消息存储在会话中。 12
其实我错了。闪过的消息是 cookie 的,可在后续请求中使用,但只能读取一次。
【参考方案1】:
您传递的 flash 消息是错误的!
done()
的第三个参数应该是一个具有type
和message
字段的对象:
return done(null, false, message: 'Wrong email' );
类型默认为error
。
此 API 似乎没有明确记录,但在 Passport.js 文档的 配置 章节中的 3rd example of the Verify Callback section 中显示。
我创建了a repo 并带有一个可重现的工作示例。
【讨论】:
我已经尝试过了,但没有用...因为说我尝试过的错误,您应该阅读Passport documentation,其中没有提及任何有关特定对象名称的内容。不过还是谢谢。 @Maramal 我已经更新了答案。我已经包含了一个最低限度的工作示例。如果该示例对您不起作用,则说明有问题。如果是这样,则问题出在代码的其他地方。 我可能不是最好的开发人员,但我理解这段代码。但是,既然我已经花掉了那个名声,我会把它给你,因为你创建了一个 repo 并努力向我解释,就像我是个白痴一样,我很感激...... 我不得不说我可能过于复杂了。我刚刚提到了req.flash('error')[0]
,效果很好。
@Maramal 谢谢,希望对你有所帮助【参考方案2】:
我一直在搜索,找到了一个解决方案,但它在第二次登录尝试时有效。
我修改后的问题步骤:
使用 NPM 安装 connect-flash。
导入后设置 Express 中间件:
import * as flash from 'connect-flash';
...
const app = express();
...
app.use(flash());
-
在 Express 路由中根据 documentation 配置 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 */
);
-
创建另一条路线,以便它可以显示 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);
);
-
在
done()
方法中包含flash消息,根据Passport configuration documentation:
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);
);
【讨论】:
为什么说“仅在第二次登录尝试时有效”?这就是闪存消息的工作方式。通常你会failureRedirect
到显示 flash 消息的页面。
我明白了,我的错。不是在预身份验证过程中检查闪存消息的选项,因为它将仅第二次读取闪存消息。所以我必须始终使用failureRedirect
。然后它第一次工作。我不应该再次感谢你......但谢谢你。以上是关于Express + PassportJS 无法读取 flash 消息的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 PassportJS 读取未定义、NestJS 的属性“validateUser”
Express Passportjs在路由器回调中未进行身份验证