为什么在路由中调用时我的 Passport 身份验证函数不执行?
Why is my Passport auth function not executing when called within a route?
我正在使用 Passport 来保护 MEAN 堆栈应用程序的前端和后端。该应用程序的结构如下:
monstermash
config // server configuration
public // static directory that will serve the entire Angular frontend
app
index.js // initialization of the server
models
index.js // mongoose schemas and models
passport
index.js // configuration for passport and all my strategies
routes
index.js // basic route definitions for the API (using functions defined under v1, below) and UI (routes defined inline here for simplicity's sake)
v1
index.js // all the functions called to power the API routes
这里是 app/index.js
因为我知道有时需要以正确的顺序调用应用程序中间件:
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var mongoose = require('mongoose');
var app = express();
var CONFIG = require('config').BASE;
var bcrypt = require('bcrypt-nodejs');
var passport = require('passport');
var flash = require('connect-flash');
var models = require('./models');
app.passport = require('./passport');
app.port = CONFIG.PORT;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(allowCrossDomain);
app.use(express.static('public'));
app.use(cookieParser());
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
var routes = require('./routes');
app.use(express.static('public', {redirect:false}));
routes(app)
module.exports = app
passport/index.js
看起来像这样。许多注释掉的位只是为了将其精简为调试而删除:
var models = require('../models')
passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, LocalAPIKeyStrategy = require('passport-localapikey-update').Strategy;
passport.use('localapikey', new LocalAPIKeyStrategy(
{apiKeyHeader:'x-auth-token'},
function(apikey, done) {
console.log('api key');
models.User.findOne({ apikey: apikey }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user);
});
}
));
passport.use('local-signup', new LocalStrategy(
function (req, username, password, done) {
console.log('trying local');
models.User.findOne({
local: {username: username}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
console.log('no user');
return done (null, false);
}
if (!user.validPassword(password)) {
console.log('bad pwd');
return done(null, false);
}
return done (null, user);
}
})
}
));
module.exports = passport;
此处包含 localaipkey 策略只是为了说明 它 的工作原理和配置方式与本地注册策略大致相同。
那我的routes/index.js
就是这样的。 HTML 登录表单在这里是内联的,因为这只是一个初步测试。请注意,除了检查验证之外,我没有做任何其他事情。在这里包括 API 路线之一也确实展示了它是如何设置的。这里的 UI 代码是直接从 Passport 教程中提取的,因为我回到绘图板并删除了我自己的代码。
var v1 = require('./v1');
// API routes as an example. This authentication is called before the route and works fine.
module.exports = function(app) {
/* API: V1 */
app.route('/v1/monster/:id')
.put(
app.passport.authenticate('localapikey', { session: false }),
v1.monster.update)
.delete(
app.passport.authenticate('localapikey', { session: false }),
v1.monster.delete
);
// My test login routes. Here, authenticate is called inside the route because it's the handler for logging in.
app.route('/login')
.post(
function (req, res) {
console.log(req.body);
app.passport.authenticate('local-signup', {
successRedirect: '/root',
failureRedirect: '/fail'
});
})
.get(function (req,res) {
res.send('<!-- views/login.ejs -->\
<!doctype html>\
<html>\
<head>\
<title>Node Authentication</title>\
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <!-- load bootstrap css -->\
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->\
<style>\
body { padding-top:80px; }\
</style>\
</head>\
<body>\
<div class="container">\
\
<form action="/login" method="post">\
<div>\
<label>Username:</label>\
<input type="text" name="username"/>\
</div>\
<div>\
<label>Password:</label>\
<input type="password" name="password"/>\
</div>\
<div>\
<input type="submit" value="Log In"/>\
</div>\
</form>\
\
</div>\
</body>\
</html>');
});
因此该表单会提交带有表单数据的 POST:/login
请求。表单正文在 req.body
中,但我在验证函数中的 console.log
消息从未被记录。表单提交只是挂了又挂了;该路由上没有 res.send()
,因为身份验证要么通过,要么失败,永远不会到达那里,但是整个 app.passport.authenticate()
功能完全被绕过了。
我在这方面做了很多试验和错误,我发现如果我用一个甚至没有注册的策略的名称调用 app.passport.authenticate()
,同样的事情发生:没有失败消息,它只是继续沿着路线前进,就像它根本不存在一样。所以 可能 问题是这正在发生并且它没有识别正在注册的 local-signup
策略,尽管我不知道为什么会这样以及 localapikey
找到策略。
旁注,我实际上是在用表单中设置的 username
和 password
进行测试;我从某个尝试空提交或无密码提交但没有看到他们的验证功能执行的人那里发现了一个 SO 问题,所以我确定不是那个问题。
所以,我的问题的答案基本上是"because you can't call the authenticate function inside a route."
我不会删除这个问题,因为我知道我是从某处的 Passport 教程中得到这个想法的,因此其他人以后可能会遇到同样的问题。
我正在使用 Passport 来保护 MEAN 堆栈应用程序的前端和后端。该应用程序的结构如下:
monstermash
config // server configuration
public // static directory that will serve the entire Angular frontend
app
index.js // initialization of the server
models
index.js // mongoose schemas and models
passport
index.js // configuration for passport and all my strategies
routes
index.js // basic route definitions for the API (using functions defined under v1, below) and UI (routes defined inline here for simplicity's sake)
v1
index.js // all the functions called to power the API routes
这里是 app/index.js
因为我知道有时需要以正确的顺序调用应用程序中间件:
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var mongoose = require('mongoose');
var app = express();
var CONFIG = require('config').BASE;
var bcrypt = require('bcrypt-nodejs');
var passport = require('passport');
var flash = require('connect-flash');
var models = require('./models');
app.passport = require('./passport');
app.port = CONFIG.PORT;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(allowCrossDomain);
app.use(express.static('public'));
app.use(cookieParser());
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
var routes = require('./routes');
app.use(express.static('public', {redirect:false}));
routes(app)
module.exports = app
passport/index.js
看起来像这样。许多注释掉的位只是为了将其精简为调试而删除:
var models = require('../models')
passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, LocalAPIKeyStrategy = require('passport-localapikey-update').Strategy;
passport.use('localapikey', new LocalAPIKeyStrategy(
{apiKeyHeader:'x-auth-token'},
function(apikey, done) {
console.log('api key');
models.User.findOne({ apikey: apikey }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user);
});
}
));
passport.use('local-signup', new LocalStrategy(
function (req, username, password, done) {
console.log('trying local');
models.User.findOne({
local: {username: username}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
console.log('no user');
return done (null, false);
}
if (!user.validPassword(password)) {
console.log('bad pwd');
return done(null, false);
}
return done (null, user);
}
})
}
));
module.exports = passport;
此处包含 localaipkey 策略只是为了说明 它 的工作原理和配置方式与本地注册策略大致相同。
那我的routes/index.js
就是这样的。 HTML 登录表单在这里是内联的,因为这只是一个初步测试。请注意,除了检查验证之外,我没有做任何其他事情。在这里包括 API 路线之一也确实展示了它是如何设置的。这里的 UI 代码是直接从 Passport 教程中提取的,因为我回到绘图板并删除了我自己的代码。
var v1 = require('./v1');
// API routes as an example. This authentication is called before the route and works fine.
module.exports = function(app) {
/* API: V1 */
app.route('/v1/monster/:id')
.put(
app.passport.authenticate('localapikey', { session: false }),
v1.monster.update)
.delete(
app.passport.authenticate('localapikey', { session: false }),
v1.monster.delete
);
// My test login routes. Here, authenticate is called inside the route because it's the handler for logging in.
app.route('/login')
.post(
function (req, res) {
console.log(req.body);
app.passport.authenticate('local-signup', {
successRedirect: '/root',
failureRedirect: '/fail'
});
})
.get(function (req,res) {
res.send('<!-- views/login.ejs -->\
<!doctype html>\
<html>\
<head>\
<title>Node Authentication</title>\
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css"> <!-- load bootstrap css -->\
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css"> <!-- load fontawesome -->\
<style>\
body { padding-top:80px; }\
</style>\
</head>\
<body>\
<div class="container">\
\
<form action="/login" method="post">\
<div>\
<label>Username:</label>\
<input type="text" name="username"/>\
</div>\
<div>\
<label>Password:</label>\
<input type="password" name="password"/>\
</div>\
<div>\
<input type="submit" value="Log In"/>\
</div>\
</form>\
\
</div>\
</body>\
</html>');
});
因此该表单会提交带有表单数据的 POST:/login
请求。表单正文在 req.body
中,但我在验证函数中的 console.log
消息从未被记录。表单提交只是挂了又挂了;该路由上没有 res.send()
,因为身份验证要么通过,要么失败,永远不会到达那里,但是整个 app.passport.authenticate()
功能完全被绕过了。
我在这方面做了很多试验和错误,我发现如果我用一个甚至没有注册的策略的名称调用 app.passport.authenticate()
,同样的事情发生:没有失败消息,它只是继续沿着路线前进,就像它根本不存在一样。所以 可能 问题是这正在发生并且它没有识别正在注册的 local-signup
策略,尽管我不知道为什么会这样以及 localapikey
找到策略。
旁注,我实际上是在用表单中设置的 username
和 password
进行测试;我从某个尝试空提交或无密码提交但没有看到他们的验证功能执行的人那里发现了一个 SO 问题,所以我确定不是那个问题。
所以,我的问题的答案基本上是"because you can't call the authenticate function inside a route."
我不会删除这个问题,因为我知道我是从某处的 Passport 教程中得到这个想法的,因此其他人以后可能会遇到同样的问题。