131 lines
4.8 KiB
JavaScript
131 lines
4.8 KiB
JavaScript
// Module dependencies.
|
|
var pause = require('pause')
|
|
, util = require('util')
|
|
, Strategy = require('passport-strategy');
|
|
|
|
|
|
/**
|
|
* Create a new `SessionStrategy` object.
|
|
*
|
|
* An instance of this strategy is automatically used when creating an
|
|
* `{@link Authenticator}`. As such, it is typically unnecessary to create an
|
|
* instance using this constructor.
|
|
*
|
|
* @classdesc This `Strategy` authenticates HTTP requests based on the contents
|
|
* of session data.
|
|
*
|
|
* The login session must have been previously initiated, typically upon the
|
|
* user interactively logging in using a HTML form. During session initiation,
|
|
* the logged-in user's information is persisted to the session so that it can
|
|
* be restored on subsequent requests.
|
|
*
|
|
* Note that this strategy merely restores the authentication state from the
|
|
* session, it does not authenticate the session itself. Authenticating the
|
|
* underlying session is assumed to have been done by the middleware
|
|
* implementing session support. This is typically accomplished by setting a
|
|
* signed cookie, and verifying the signature of that cookie on incoming
|
|
* requests.
|
|
*
|
|
* In {@link https://expressjs.com/ Express}-based apps, session support is
|
|
* commonly provided by {@link https://github.com/expressjs/session `express-session`}
|
|
* or {@link https://github.com/expressjs/cookie-session `cookie-session`}.
|
|
*
|
|
* @public
|
|
* @class
|
|
* @augments base.Strategy
|
|
* @param {Object} [options]
|
|
* @param {string} [options.key='passport'] - Determines what property ("key") on
|
|
* the session data where login session data is located. The login
|
|
* session is stored and read from `req.session[key]`.
|
|
* @param {function} deserializeUser - Function which deserializes user.
|
|
*/
|
|
function SessionStrategy(options, deserializeUser) {
|
|
if (typeof options == 'function') {
|
|
deserializeUser = options;
|
|
options = undefined;
|
|
}
|
|
options = options || {};
|
|
|
|
Strategy.call(this);
|
|
|
|
/** The name of the strategy, set to `'session'`.
|
|
*
|
|
* @type {string}
|
|
* @readonly
|
|
*/
|
|
this.name = 'session';
|
|
this._key = options.key || 'passport';
|
|
this._deserializeUser = deserializeUser;
|
|
}
|
|
|
|
// Inherit from `passport.Strategy`.
|
|
util.inherits(SessionStrategy, Strategy);
|
|
|
|
/**
|
|
* Authenticate request based on current session data.
|
|
*
|
|
* When login session data is present in the session, that data will be used to
|
|
* restore login state across across requests by calling the deserialize user
|
|
* function.
|
|
*
|
|
* If login session data is not present, the request will be passed to the next
|
|
* middleware, rather than failing authentication - which is the behavior of
|
|
* most other strategies. This deviation allows session authentication to be
|
|
* performed at the application-level, rather than the individual route level,
|
|
* while allowing both authenticated and unauthenticated requests and rendering
|
|
* responses accordingly. Routes that require authentication will need to guard
|
|
* that condition.
|
|
*
|
|
* This function is protected, and should not be called directly. Instead,
|
|
* use `passport.authenticate()` middleware and specify the {@link SessionStrategy#name `name`}
|
|
* of this strategy and any options.
|
|
*
|
|
* @protected
|
|
* @param {http.IncomingMessage} req - The Node.js {@link https://nodejs.org/api/http.html#class-httpincomingmessage `IncomingMessage`}
|
|
* object.
|
|
* @param {Object} [options]
|
|
* @param {boolean} [options.pauseStream=false] - When `true`, data events on
|
|
* the request will be paused, and then resumed after the asynchronous
|
|
* `deserializeUser` function has completed. This is only necessary in
|
|
* cases where later middleware in the stack are listening for events,
|
|
* and ensures that those events are not missed.
|
|
*
|
|
* @example
|
|
* passport.authenticate('session');
|
|
*/
|
|
SessionStrategy.prototype.authenticate = function(req, options) {
|
|
if (!req.session) { return this.error(new Error('Login sessions require session support. Did you forget to use `express-session` middleware?')); }
|
|
options = options || {};
|
|
|
|
var self = this,
|
|
su;
|
|
if (req.session[this._key]) {
|
|
su = req.session[this._key].user;
|
|
}
|
|
|
|
if (su || su === 0) {
|
|
// NOTE: Stream pausing is desirable in the case where later middleware is
|
|
// listening for events emitted from request. For discussion on the
|
|
// matter, refer to: https://github.com/jaredhanson/passport/pull/106
|
|
|
|
var paused = options.pauseStream ? pause(req) : null;
|
|
this._deserializeUser(su, req, function(err, user) {
|
|
if (err) { return self.error(err); }
|
|
if (!user) {
|
|
delete req.session[self._key].user;
|
|
} else {
|
|
var property = req._userProperty || 'user';
|
|
req[property] = user;
|
|
}
|
|
self.pass();
|
|
if (paused) {
|
|
paused.resume();
|
|
}
|
|
});
|
|
} else {
|
|
self.pass();
|
|
}
|
|
};
|
|
|
|
// Export `SessionStrategy`.
|
|
module.exports = SessionStrategy;
|