項目使用的是passport.js(http://passportjs.org/docs),因此對passport這個中間件研究了一番,在本項目中passport同express-session配合使用javascript
其中配置express-sission:php
app.use(session({
secret: secret,
store: store, //數據庫存儲session,
resave: false,
saveUninitialized: true,
cookie: cookie,
key: key
}));
對於數據庫存儲session:下面是代碼(參考:https://www.npmjs.com/package/connect-mongo)
var mongoose =
其中的secret,key爲字符串,cookie爲一個object對象:配置以下:
cookie: {
path: "/",
expires: 15 * 60 * 1000 //失效時間
}
}
passport.js的翻譯:
安裝:npm install passport
Authenticating requests is as simple as calling passport.authenticate()
and specifying which strategy to employ. authenticate()
's function signature is standard Connect middleware, which makes it convenient to use as route middleware in Express applications.java
將passport.authenticate()當作一箇中間件來使用:
app.post('/login',
passport.authenticate('local'), function(req, res) { //local待續...
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user. //會將user信息(下面會講怎麼獲取這個user信息)掛載在req.user上
res.redirect('/users/' + req.user.username);
});
By default, if authentication fails, Passport will respond with a status, and any additional route handlers will not be invoked.
If authentication succeeds, the next handler will be invoked and the property will be set to the authenticated user.
當驗證失敗時,返回401,而且任何的route handles都不會調用.當驗證成功後,req.user上將會掛載uer信息.401 Unauthorizedreq.user
Note: Strategies must be configured prior to using them in a route. Continue reading the chapter onconfiguration for details.git
使用以前先要配置一下.github
A redirect is commonly issued after authenticating a request.web
app.post('/login', passport.authenticate('local', { 數據庫
successRedirect: '/', //這個是驗證成功後的重定向express
failureRedirect: '/login' //這個是驗證失敗後的重定向npm
}));json
In this case, the redirect options override the default behavior. Upon successful authentication, the user will be redirected to the home page.
If authentication fails, the user will be redirected back to the login page for another attempt.
Redirects are often combined with flash messages in order to display status information to the user.
重定向常常會配合着刷新,向客戶端發送status 信息.
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}) );
Setting the failureFlash
option to true
instructs Passport to flash an error
message using the message given by the strategy's verify callback, if any. This is often the best approach, because the verify callback can make the most accurate determination of why authentication failed.
這每每是最好的方法,由於驗證回調能夠精確測定驗證失敗的緣由。
Alternatively, the flash message can be set specifically.
passport.authenticate('local', { failureFlash: 'Invalid username or password.' });
A successFlash option is available which flashes a success message when authentication succeeds.
passport.authenticate('local', { successFlash: 'Welcome!' });
Note: Using flash messages requires a req.flash()
function. Express 2.x provided this functionality, however it was removed from Express 3.x. Use of connect-flash middleware is recommended to provide this functionality when using Express 3.x.
備註:用這個還須要使用req.flash() 因此通常不會設置.
After successful authentication, Passport will establish a persistent login session. This is useful for the common scenario of users accessing a web application via a browser.
However, in some cases, session support is not necessary. For example, API servers typically require credentials to be supplied with each request. When this is the case,
session support can be safely disabled by setting the session
option to false
app.get('/api/users/me',passport.authenticate('basic', { session: false }),function(req, res) {
res.json({
id: req.user.id,
username: req.user.username
});
});
對於常見的依靠session是有用的,可是對於api那種依賴credentials(證書).則是不可用的,這時候設置session爲false.
app.get('/api/users/me', passport.authenticate('basic', { session: false }), function(req, res) {
res.json({
id: req.user.id,
username: req.user.username
});
});
If the built-in options are not sufficient for handling an authentication request, a custom callback can be provided to allow the application to handle success or failure.
若是內置選項不足以處理的認證請求,能夠提供一種定製的回調,以容許應用程序來處理成功或失敗。
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username); });
})(req, res, next);
});
In this example, note that authenticate()
is called from within the route handler, rather than being used as route middleware. This gives the callback access to the req
and res
objects through closure.
在本實施例,請注意,authenticate()被從路徑處理程序中調用的,而不是被用做路由中間件。這使得經過關閉回調訪問req
and res
objects 。
下面是講解這個example:
If authentication failed, user
will be set to false
. If an exception occurred, err
will be set. An optional info
argument will be passed, containing additional details provided by the strategy's verify callback.
The callback can use the arguments supplied to handle the authentication result as desired. Note that when using a custom callback, it becomes the application's responsibility to establish a session (by callingreq.login()
) and send a response.
hree pieces need to be configured to use Passport for authentication:
Passport uses what are termed strategies to authenticate requests. Strategies range from verifying a username and password, delegated authentication using OAuth or federated authentication using OpenID.
Passport使用所謂的strategies(策略)來驗證請求。Strategies範圍從驗證用戶名和密碼,使用OAuth或使用OpenID聯合身份驗證委派驗證。
Before asking Passport to authenticate a request, the strategy (or strategies) used by an application must be configured.
Strategies, and their configuration, are supplied via the use()
function. For example, the following uses theLocalStrategy
for username/password authentication.
經過use方法配置Strategy.LocalStrategy傳入一個回調函數.function(username,passport,done) {} 獲取的信息,經過done()傳入到passport中,最後再進行序列化.
var passport = require('passport') ,
LocalStrategy = require('passport-local').Strategy; //Strategy
passport.use(new LocalStrategy(
function(username, password, done) { //這個被稱爲驗證回調函數.
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user); });
} ));
This example introduces an important concept. Strategies require what is known as a verify callback. The purpose of a verify callback is to find the user that possesses a set of credentials.
本例介紹一個重要的概念。策略須要一個被稱爲驗證回函數。一個驗證回調函數的目的是要找到一個擁有一組憑據的用戶。
When Passport authenticates a request, it parses the credentials contained in the request. It then invokes the verify callback with those credentials as arguments, in this case username
and password
. If the credentials are valid, the verify callback invokes done
to supply Passport with the user that authenticated.
當Passport驗證請求時,它解析請求中包含的數據。而後調用這些數據做爲參數,在這種狀況下,用戶名和密碼會做爲回調的參數。若是數據有效,驗證回調函數將調用done(null,user)。
return done(null, user);
If the credentials are not valid (for example, if the password is incorrect), done
should be invoked with false
instead of a user to indicate an authentication failure.
return done(null, false);
An additional info message can be supplied to indicate the reason for the failure. This is useful for displaying a flash message prompting the user to try again.
return done(null, false, { message: 'Incorrect password.' });
Finally, if an exception occurred while verifying the credentials (for example, if the database is not available),done
should be invoked with an error, in conventional Node style.
return done(err);
In a Connect or Express-based application, passport.initialize()
middleware is required to initialize Passport. If your application uses persistent login sessions, passport.session()
middleware must also be used.
app.configure(function() {
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router); });
Note that enabling session support is entirely optional, though it is recommended for most applications. If enabled, be sure to use express.session()
before passport.session()
to ensure that the login session is restored in the correct order.
express.session()要先於passport.session()配置
In a typical web application, the credentials used to authenticate a user will only be transmitted during the login request. If authentication succeeds, a session will be established and maintained via a cookie set in the user's browser.
在一個典型的Web應用程序,用來驗證用戶的數據只會在登陸請求期間發送的。若是驗證成功,會話將被創建並經過在用戶的瀏覽器中設置的cookie保持。
Each subsequent request will not contain credentials, but rather the unique cookie that identifies the session. In order to support login sessions, Passport will serialize and deserialize user
instances to and from the session.
每一個後續請求將不包含這些驗證數據,而是惟一的Cookie標識會話。爲了支持登陸會話,passport會執行serializeUser(序列化)和deserializeUser(反序列化)的用戶實例和會話。這個就是查數據庫,來一次請求查一次.
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user); });
});
In this example, only the user ID is serialized to the session, keeping the amount of data stored within the session small. When subsequent requests are received, this ID is used to find the user, which will be restored toreq.user
.
在本實施例中,只有在user ID被序列化到session,保持存儲在會話小內的數據量。當接收到的後續請求,這個ID被用來找到用戶,這將掛載到req.user。
The serialization and deserialization logic is supplied by the application, allowing the application to choose an appropriate database and/or object mapper, without imposition by the authentication layer.
使用這個的目的是由於,使用本地策略
The most widely used way for websites to authenticate users is via a username and password. Support for this mechanism is provided by the passport-local module.
var passport = require('passport') ,
LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy( function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Incorrect username.' }); }
if (!user.validPassword(password)) { return done(null, false, { message: 'Incorrect password.' }); }
return done(null, user); });
}
));
The verify callback for local authentication accepts username
and password
arguments, which are submitted to the application via a login form.
這個function就是扇面你提到的驗證回調函數
The login form is submitted to the server via the POST
method. Using authenticate()
with the local
strategy will handle the login request.
app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login', failureFlash: true }) );
Setting the failureFlash
option to true
instructs Passport to flash an error
message using the message
option set by the verify callback above. This is helpful when prompting the user to try again.
By default, LocalStrategy
expects to find credentials in parameters named username
and password
. If your site prefers to name these fields differently, options are available to change the defaults.
passport.use(new LocalStrategy({ usernameField: 'email', passwordField: 'passwd' }, function(username, password, done) { // ... } ));
整理:
1.配置:
先配置session:
app.use(session({
secret: secret,
store: store, //數據庫存儲session,
resave: false,
saveUninitialized: true,
cookie: cookie,
key: key
}));
再配置中間件:
app.configure(function() {
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router); });
2.配置驗證
app.post('/user/login',passport.authenticate('local',{
failureRedirect: failureRedirect,
failureFlash: failureFlash,
badRequestMessage: badRequestMessage
}),handler)
)
其中handler是驗證成功後的回調函數.
var handler = function (req, res) {
return res.send('ok')
};
3.配置策略
passport.use('local', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
callback:passportCallback
}, passportCallback)); //這個指的是驗證回調函數
passportCallback爲:function (req, username, password, done) {} (驗證回調函數)
驗證回調函數會將done的數據傳入到序列化中.
4.序列化和反序列化
//序列化是將信息存儲到session中
passport.serializeUser(function(user, done) {
done(null, user.id);
});
//反序列化是將session中信息提取出來,掛在到req.user對象上
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user); });
});
補充:對於驗證失敗的時候,會調用req.flash()方法,所以要引進中間件 express-flash(或者connect-flash)
對於passport.js,每一次請求後都會更新數據庫的失效時間,但客戶端的exprise不會更新,這個要手動的更新才能夠,設置以下:
resave: true,rolling: true
其中,rolling: true時會更新瀏覽器的cookie,
resave: true時會強制更新數據庫的session