前言
之前我们已经分析了
路由守卫函数会回调canActive
然后调用Passport的authenticate函数
然后成功会调用我们自己的handleRequest函数
那我们继续往authenticate里找
注意,这个在passport的npm包里
https://github.com/jaredhanson/passport
正文
根据index.js定位到默认导出是new Passport()
找到了lib\authenticator.js
可以找到源码
* @param {String} strategy
* @param {Object} options
* @param {Function} callback
* @Return {Function} middleware
* @Api public
*/
Authenticator.prototype.authenticate = function(strategy, options, callback) {
return this._framework.authenticate(this, strategy, options, callback);
};
也就是说strategy是策略,也就是上节传入的'local',options选项,callback回调,而this指的Passport自身,那问题来了,_framework是什么?
function Authenticator() {
this._key = 'passport';
this._strategies = {};
this._serializers = [];
this._deserializers = [];
this._infoTransformers = [];
this._framework = null;
this.init();
}
/**
* Initialize authenticator.
*
* @api protected
*/
Authenticator.prototype.init = function() {
this.framework(require('./framework/connect')());
this.use(new SessionStrategy({ key: this._key }, this.deserializeUser.bind(this)));
this._sm = new SessionManager({ key: this._key }, this.serializeUser.bind(this));
};
初始化将_framework 设为了null,然后调用了init,init内部调用了framwork,并且request了一个对象,我们先看看framwork函数
* Examples:
*
* passport.framework(require('hapi-passport')());
*
* @param {Object} name
* @return {Authenticator} for chaining
* @api public
*/
Authenticator.prototype.framework = function(fw) {
this._framework = fw;
return this;
};
没错,我们找到了framework,那直接往require('./framework/connect')()里追就好了
var initialize = require('../middleware/initialize')
, authenticate = require('../middleware/authenticate');
/**
* Framework support for Connect/Express.
*
* This module provides support for using Passport with Express. It exposes
* middleware that conform to the `fn(req, res, next)` signature.
*
* @return {Object}
* @api protected
*/
exports = module.exports = function() {
return {
initialize: initialize,
authenticate: authenticate
};
};
于是找到了initialize和v函数,我们之前调用的就是authenticate函数,所以往
require('../middleware/authenticate')追
找到了lib\middleware\authenticate.js下的
module.exports = function authenticate(passport, name, options, callback) 函数
大概样子是
module.exports = function authenticate(passport, name, options, callback) {
return function authenticate(req, res, next) {
}
}
一个闭包,我们观察一下之前传入的代码
passport.authenticate(type, options, (err, user, info, status) => {
try {
request.authInfo = info;
return resolve(callback(err, user, info, status));
} catch (err) {
reject(err);
}
})(request, response, (err) => (err ? reject(err) : resolve()))
可以看到首先调用函数返回了一个函数,然后哦立刻调用返回的函数传入request, response, (err) => (err ? reject(err) : resolve()
让其得到执行
我们先理一下passport如何找到passport-loca策略的吧
name是策略的名字
首先执行到了
function authenticate(passport, name, options, callback) {
if (!Array.isArray(name)) {
name = [ name ];
multi = false;
}
return function authenticate(req, res, next) {
(function attempt(i) {
var layer = name[i];
if (!layer) { return allFailed();
var strategy, prototype;
if (typeof layer.authenticate == 'function') {
strategy = layer;
} else {
prototype = passport._strategy(layer);
if (!prototype) { return next(new Error('Unknown authentication strategy "' + layer + '"')); }
strategy = Object.create(prototype);
}
}
})(0)
}
}
首先将名字转为数组,然后取第0项开始执行,后续其实会遍历所有策略,但是不涉及我们主要分析代码,有兴趣自己clone一份看看,
取了第0项知道看是不是一个函数,如果是直接赋值为策略,如果不是则调用passport._strategy
我们是一个字符串的local,所以会调用passport._strategy函数
Authenticator.prototype._strategy = function(name) {
return this._strategies[name];
};
_strategs直接在_strategies里查找的,应该是一个对象,键是字符串,值则是策略
那肯定有一个注册到_strategies上的函数,全局搜索找到了
* @param {String|Strategy} name
* @param {Strategy} strategy
* @return {Authenticator} for chaining
* @api public
*/
Authenticator.prototype.use = function(name, strategy) {
if (!strategy) {
strategy = name;
name = strategy.name;
}
if (!name) { throw new Error('Authentication strategies must have a name'); }
this._strategies[name] = strategy;
return this;
};
这里判断是否传入了名字,如果没传入则取strategy对象的名字,并且设置到_strategies,方便在authenticate中使用
当找到了策略就会设置一个空对象,然后把策略设置为原型
strategy = Object.create(prototype);
strategy.success = function(user, info){}
strategy.fail = function(challenge, status){}
strategy.redirect = function(url, status){}
strategy.pass = function(){}
strategy.error = function(err)(){}
strategy.authenticate(req, options);
然后设置一些函数,最后调用了策略的authenticate函数,并且传入了req和options
因为我们设置的是local,所以调用的是passport-local内的逻辑了
所以这篇就算完了~
总结
passport中的authenticate函数主要从存储的对象中找到对应的策略,并且进行调用,使用use的时候会将策略注入到passport对象中
结语
撒花~