我使用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策略只是为了说明 it 的工作原理,其配置方式与本地注册策略的配置方式大致相同。
然后我的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
策略正在注册,尽管我不知道为什么会这样,而{{{ 1}}找到策略。
旁注,我实际上是在表单中设置了localapikey
和username
进行测试;我发现有一个问题来自那些尝试空洞或无密码提交并且没有看到他们的验证功能执行的人,所以我确定它不是那样。
答案 0 :(得分:5)
所以,我的问题的答案基本上是“因为你不能在路由中调用authenticate函数。”
我没有删除这个问题,因为我知道我从某个Passport教程中获得了这个想法,因此其他人可能会在以后成为同样的事情。