关于Laravel框架中Guard的底层实现 (2)

Laravel中中间件的处理入口都是handle方法,参数中会一数组形式传过来多个使用的guard,比如这样:

Route::get('/user/profile', 'UserController@profile')->middleware('auth:session,foo,bar');

middleware()中冒号前后分别是中间件和参数。

handle方法很简单嘛,就是调用了authenticate():

// \Illuminate\Auth\Middleware\Authenticate.php /** * Determine if the user is logged in to any of the given guards. * * @param \Illuminate\Http\Request $request * @param array $guards * @return void * * @throws \Illuminate\Auth\AuthenticationException */ protected function authenticate($request, array $guards) { if (empty($guards)) { $guards = [null]; } foreach ($guards as $guard) { if ($this->auth->guard($guard)->check()) { return $this->auth->shouldUse($guard); } } $this->unauthenticated($request, $guards); }

authenticate()方法遍历传过来的guard,然后check(),只要满足其中一个,就直接返回,否则就会抛出AuthenticationException异常。

⚠️注意 $this->auth->guard($guard)->check()

这个是关键,它是通过在auth属性上链式调用的,我们来「公众号」(正义的程序猿)一步一步分析下:

// \Illuminate\Auth\Middleware\Authenticate.php namespace Illuminate\Auth\Middleware; use Closure; use Illuminate\Auth\AuthenticationException; use Illuminate\Contracts\Auth\Factory as Auth; use Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests; class Authenticate implements AuthenticatesRequests { /** * The authentication factory instance. * * @var \Illuminate\Contracts\Auth\Factory */ protected $auth; /** * Create a new middleware instance. * * @param \Illuminate\Contracts\Auth\Factory $auth * @return void */ public function __construct(Auth $auth) { $this->auth = $auth; } ... }

这里的$auth其实是\Illuminate\Contracts\Auth\Factory接口的一个实例,通过构造函数注入进来,通过dd($this->auth)方式发现这个其实就是Illuminate\Auth\AuthManager实例,它实现了Illuminate\Contracts\Auth\Factory接口:

// \Illuminate\Contracts\Auth\Factory.php namespace Illuminate\Contracts\Auth; interface Factory { /** * Get a guard instance by name. * * @param string|null $name * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard */ public function guard($name = null); /** * Set the default guard the factory should serve. * * @param string $name * @return void */ public function shouldUse($name); }

这个接口有guard()方法,所以上面可以直接链式调用。

通过接口定义的声明,我们可以知道guard()返回\Illuminate\Contracts\Auth\Guard或者\Illuminate\Contracts\Auth\StatefulGuard这两个接口,具体在AuthManager中的实现是这样的:

// \Illuminate\Auth\AuthManager.php /** * Attempt to get the guard from the local cache. * * @param string|null $name * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard */ public function guard($name = null) { $name = $name ?: $this->getDefaultDriver(); return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name); }

通过我们在middleware()中传过来的参数创建对应的guard实例,没有就是默认driver对应的guard,最后check()。

这节最后讲一下

AuthManager是什么时候创建的?

Laravel框架初始化时,很多服务都是以服务提供者(ServiceProvider)的形式创建的,AuthManager就是AuthServiceProvider创建的:

// \Illuminate\Auth\AuthServiceProvider.php namespace Illuminate\Auth; class AuthServiceProvider extends ServiceProvider { /** * Register the service provider. * * @return void */ public function register() { $this->registerAuthenticator(); .... } /** * Register the authenticator services. * * @return void */ protected function registerAuthenticator() { $this->app->singleton('auth', function ($app) { // Once the authentication service has actually been requested by the developer // we will set a variable in the application indicating such. This helps us // know that we need to set any queued cookies in the after event later. $app['auth.loaded'] = true; return new AuthManager($app); }); .... } .... }

AuthServiceProvider中在注册时调用registerAuthenticator(),创建auth单例指向AuthManager实例。

通过上面的一波分析,我们知道guard的创建是受AuthManager管理的,AuthManager在这里的指责就是解析driver并创建guard。

所以现在整个middleware('auth')的流程大致如下:

middleware auth

5. Guard接口

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyxfd.html