李恒道 发表于 2022-12-4 01:34:19

nestjs passport及@nestjs/passport源码级分析(三)

# 前言
之前我们已经分析了
路由守卫函数会回调canActive
然后调用Passport的authenticate函数
然后成功会调用我们自己的handleRequest函数
那我们继续往authenticate里找
注意,这个在passport的npm包里
https://github.com/jaredhanson/passport
# 正文
根据index.js定位到默认导出是new Passport()
找到了lib\authenticator.js
可以找到源码
```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是什么?
```js
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函数
```js
* 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')()里追就好了
```js
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) 函数
大概样子是
```js
module.exports = function authenticate(passport, name, options, callback) {
      return function authenticate(req, res, next) {
      }
}
```
一个闭包,我们观察一下之前传入的代码
```js
      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是策略的名字
首先执行到了
```js
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;
         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函数
```js
Authenticator.prototype._strategy = function(name) {
return this._strategies;
};
```
_strategs直接在_strategies里查找的,应该是一个对象,键是字符串,值则是策略
那肯定有一个注册到_strategies上的函数,全局搜索找到了
```js
* @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 = strategy;
return this;
};
```
这里判断是否传入了名字,如果没传入则取strategy对象的名字,并且设置到_strategies,方便在authenticate中使用
当找到了策略就会设置一个空对象,然后把策略设置为原型
```js
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对象中
# 结语
撒花~

页: [1]
查看完整版本: nestjs passport及@nestjs/passport源码级分析(三)