如何将Passport.js登录验证的服务端错误传递至客户端?
Passport.js 登录错误提示不显示问题排查与解决
我用Passport.js编写了登录相关代码,成功登录后的successRedirect功能正常,但输入错误密码时没有任何提示,不清楚如何将服务端的验证错误展示到客户端。相关代码如下:
passport-config.js(LocalStrategy初始化代码)
const LocalStratigy = require('passport-local').Strategy const bcrypt = require('bcrypt') const initialize = (passport, getUserByEmail, getUserById) => { const authenticateUser = async (email, password, done) => { const user = getUserByEmail(email) // 后续会实现这个函数,不用在意 if (user == null) { return done(null, false, { messege: "No user with that email" }) // done是参数中传入的回调函数 } try { if (await bcrypt.compare(password, user.password)) { return done(null, user) } else { return done(null, false, { messege: "wrrong password " }) } } catch (error) { return done(error) } } passport.use(new LocalStratigy({ usernameField: 'email' }, authenticateUser)) passport.serializeUser((user, done) => done(null, user.id)) passport.deserializeUser((id, done) => { return done(null, getUserById(id)) }) } module.exports = initialize
serveur.js(服务端路由代码)
app.post('/signin', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/signin', failureFlash: true }))
signin.html(客户端页面,其中JavaScript代码无法正常工作)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="signup.css"> </head> <body> <div id="messeges"> </div> <form action="signin" method="post"> <div class="box"> <div class="from"> <h2>Sign in</h2> <div class="inputbox"> <input type="email" name="email" id="email" required="required"> <span>Email Adress</span> <i></i> </div> <div class="inputbox"> <input type="password" id="password" name="password" required="required"> <span>Password</span> <i></i> </div> <div class="links"> <a href="./signup.html">Forgot Password</a> <a href="./signup.html">sign up</a> </div> <input type="submit" value="Login"> </div> </div> </form> <script> const messege = document.getElementById('messeges') if (messages.error) { messege.innerHTML = "<h1>messages.error</h1>" } </script> </body> </html>
问题原因与解决步骤
1. 服务端缺失Flash消息中间件配置
你在passport.authenticate中启用了failureFlash: true,但未配置express-flash中间件,导致服务端无法将错误消息传递到客户端。
解决:
- 安装依赖包:
npm install express-flash express-session
- 在serveur.js中添加中间件配置(需放在Passport初始化之前):
const flash = require('express-flash') const session = require('express-session') // 配置session app.use(session({ secret: '你的随机密钥', // 替换为自定义密钥 resave: false, saveUninitialized: false })) // 启用Flash消息 app.use(flash()) // 初始化Passport(确保在session和flash配置之后) const initializePassport = require('./passport-config') initializePassport(passport, getUserByEmail, getUserById)
2. 客户端未正确获取服务端错误消息
当前HTML中的JavaScript存在变量名拼写错误,且未从服务端获取错误数据:
messege与messages拼写不一致- 直接访问未定义的
messages.error变量
以下提供两种解决方案:
方案一:改用模板引擎(推荐)
将静态HTML改为模板文件(以EJS为例),直接在服务端渲染时传递错误消息:
- 安装EJS:
npm install ejs - 配置模板引擎:
app.set('view engine', 'ejs')
- 修改登录路由,手动处理认证结果并传递消息:
// 替换原POST路由 app.post('/signin', (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (err) return next(err) if (!user) { req.flash('error', info.messege) return res.redirect('/signin') } req.logIn(user, (err) => { if (err) return next(err) return res.redirect('/') }) })(req, res, next) }) // GET路由渲染登录页并传递错误消息 app.get('/signin', (req, res) => { res.render('signin', { error: req.flash('error')[0] }) })
- 修改signin.ejs内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="signup.css"> </head> <body> <% if (error) { %> <div id="messeges"> <h1><%= error %></h1> </div> <% } %> <!-- 表单内容保持不变 --> <form action="/signin" method="post"> <div class="box"> <div class="from"> <h2>Sign in</h2> <div class="inputbox"> <input type="email" name="email" id="email" required="required"> <span>Email Adress</span> <i></i> </div> <div class="inputbox"> <input type="password" id="password" name="password" required="required"> <span>Password</span> <i></i> </div> <div class="links"> <a href="./signup.html">Forgot Password</a> <a href="./signup.html">sign up</a> </div> <input type="submit" value="Login"> </div> </div> </form> </body> </html>
方案二:静态HTML通过查询参数传递错误
若坚持使用静态HTML,可通过URL查询参数传递错误消息:
- 修改服务端路由:
app.post('/signin', (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (err) return next(err) if (!user) { const encodedError = encodeURIComponent(info.messege) return res.redirect(`/signin?error=${encodedError}`) } req.logIn(user, (err) => { if (err) return next(err) return res.redirect('/') }) })(req, res, next) })
- 更新signin.html中的JavaScript:
<script> const messageDiv = document.getElementById('messeges') const urlParams = new URLSearchParams(window.location.search) const error = urlParams.get('error') if (error) { messageDiv.innerHTML = `<h1>${error}</h1>` // 清除查询参数,避免刷新页面重复显示错误 window.history.replaceState({}, document.title, window.location.pathname) } </script>
3. 代码拼写错误修正
LocalStratigy改为LocalStrategy(拼写错误)messege统一改为message(避免拼写混乱)wrrong password改为Wrong password(拼写错误)
修正后的passport-config.js关键代码:
const LocalStrategy = require('passport-local').Strategy // ... if (user == null) { return done(null, false, { message: "No user with that email" }) } // ... } else { return done(null, false, { message: "Wrong password" }) }
内容的提问来源于stack exchange,提问作者dhia mlayah
相关产品推荐
相关产品推荐

