node的passport.js驗證


項目使用的是passport.js(http://passportjs.org/docs),所以對passport這個中間件研究了一番,在本項目中passport同express-session配合使用

其中配置express-sission:

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 require('mongoose');
  mongoose.connect(connectionOptions);
 
 app.use(session({
    storenew MongoStore({ mongooseConnectionmongoose.connection })
}));

 

其中的secret,key為字符串,cookie為一個object對象:配置如下:
cookie: {
path: "/",
expires: 15 * 60 * 1000 //失效時間
}
}

passport.js的翻譯:

安裝:npm install passport

Authenticate

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.

將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 401 Unauthorized status, and any additional route handlers will not be invoked.
If authentication succeeds, the next handler will be invoked and thereq.user property will be set to the authenticated user.
當驗證失敗時,返回401,並且任何的route handles都不會調用.當驗證成功后,req.user上將會掛載uer信息.

Note: Strategies must be configured prior to using them in a route. Continue reading the chapter onconfiguration for details.

使用之前先要配置一下.

Redirects

A redirect is commonly issued after authenticating a request.

app.post('/login', passport.authenticate('local', {

                 successRedirect: '/',                                  //這個是驗證成功后的重定向

      failureRedirect: '/login'                             //這個是驗證失敗后的重定向

}));

 

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.

Flash Messages (刷新)

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()  所以一般不會設置.

 

Disable Sessions 禁用session

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

      });

});

Custom Callback

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 infoargument 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.

Configure

hree pieces need to be configured to use Passport for authentication:

  1. Authentication strategies     //認證策略
  2. Application middleware       //中間件
  3. Sessions (optional)             //session

Strategies

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); });

} ));

Verify Callback

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 falseinstead 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);

 

Middleware

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()配置

 

Sessions

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.

Username & Password

使用這個的目的是因為,使用本地策略

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.

Configuration

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就是扇面你提到的驗證回調函數 

 

Route

The login form is submitted to the server via the POST method. Using authenticate() with the localstrategy 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 messageoption set by the verify callback above. This is helpful when prompting the user to try again.

 

Parameters

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM