Laravel 5.3 auth中间件底层实现详解(转)
1. 注册认证中间件, 在文件 app/Http/Kernel.php 内完成:
protected $routeMiddleware = [ 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'checkuid' => \App\Http\Middleware\CheckUid::class, ];
2. 认证中间件的源码
文件:vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php 。其中:
use Illuminate\Contracts\Auth\Factory as Auth; public function __construct(Auth $auth) { $this->auth = $auth; //Auth 工厂类,这里注入的是 Illuminate\Auth\AuthManager } public function handle($request, Closure $next, ...$guards) { $this->authenticate($guards); return $next($request); } protected function authenticate(array $guards) { if (empty($guards)) {//如果没有指定guard 则使用默认 return $this->auth->authenticate(); //通过Illuminate\Auth\AuthManager\__call() 调用 创建guard 实例,并调用guard 实例的 authenticate() 方法进行认证 } foreach ($guards as $guard) { if ($this->auth->guard($guard)->check()) {//使用指定的guard中第一个能成功认证的 return $this->auth->shouldUse($guard);//将指定guard设置为 本次请求的默认guard。(本次请求后续获取authed user时,都通过这里设置的guard进行) } } throw new AuthenticationException('Unauthenticated.', $guards); }
2.1 $this->auth->authenticate(); //进行身份认证
文件: vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php
public function __call($method, $parameters) { return $this->guard()->{$method}(...$parameters); }
2.2 $this->guard() //获取guard实例
文件: vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php
public function guard($name = null) { $name = $name ?: $this->getDefaultDriver(); return isset($this->guards[$name]) ? $this->guards[$name] //单例 : $this->guards[$name] = $this->resolve($name); //获取 guard 实例 } public function getDefaultDriver() { return $this->app['config']['auth.defaults.guard']; //从配置文件内读取默认guard } protected function resolve($name) { $config = $this->getConfig($name); //获取指定guard配置信息 if (is_null($config)) { throw new InvalidArgumentException("Auth guard [{$name}] is not defined."); } if (isset($this->customCreators[$config['driver']])) {//如果设置了自定义工厂,则使用之 return $this->callCustomCreator($name, $config); } //类似 createSessionDriver, createTokenDriver 等格式 $driverMethod = 'create'.ucfirst($config['driver']).'Driver'; if (method_exists($this, $driverMethod)) { return $this->{$driverMethod}($name, $config); } throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined."); } public function createSessionDriver($name, $config) { $provider = $this->createUserProvider($config['provider']); $guard = new SessionGuard($name, $provider, $this->app['session.store']); //When using the remember me functionality of the authentication services we //will need to be set the encryption instance of the guard, which allows //secure, encrypted cookie values to get generated for those cookies. if (method_exists($guard, 'setCookieJar')) { $guard->setCookieJar($this->app['cookie']); } if (method_exists($guard, 'setDispatcher')) { $guard->setDispatcher($this->app['events']); } if (method_exists($guard, 'setRequest')) { $guard->setRequest($this->app->refresh('request', $guard, 'setRequest')); } return $guard; }
2.3 $this->guard()->authenticate() //使用获取的 guard 实例进行身份认证
文件: vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
类中 use 了 GuardHelpers trait
文件:vendor/laravel/framework/src/Illuminate/Auth/GuardHelpers.php
public function authenticate() { if (! is_null($user = $this->user())) { return $user; } throw new AuthenticationException; }
文件: vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php //此方法是真正进行身份认证的地方!!!!
public function user() { if ($this->loggedOut) { return; } // If we've already retrieved the user for the current request we can just // return it back immediately. We do not want to fetch the user data on // every call to this method because that would be tremendously slow. if (! is_null($this->user)) { return $this->user; } $id = $this->session->get($this->getName()); //从session中获取用户ID。已登录用户的用户ID会被存储在Session内。 // First we will try to load the user using the identifier in the session if // one exists. Otherwise we will check for a "remember me" cookie in this // request, and if one exists, attempt to retrieve the user using that. $user = null; if (! is_null($id)) { if ($user = $this->provider->retrieveById($id)) { //通过Illuminate\Auth\EloquentUserProvider 的retrieveById() 方法,获取用户信息,并返回User Model $this->fireAuthenticatedEvent($user); } } // If the user is null, but we decrypt a "recaller" cookie we can attempt to // pull the user data on that cookie which serves as a remember cookie on // the application. Once we have a user we can return it to the caller. $recaller = $this->getRecaller();//获取认证cookie(登录时选中记住我,服务端会向浏览器设置一个认证cookie,其中包括 remember_token,下次可以直接使用这个认证cookie进行登录) if (is_null($user) && ! is_null($recaller)) { $user = $this->getUserByRecaller($recaller); //使用 remember_token 从数据库中获取用户信息 (最终是委托 Illuminate\Auth\EloquentUserProvider::retrieveByToken() 方法来取数据) if ($user) { $this->updateSession($user->getAuthIdentifier()); //将用户ID保存到Session $this->fireLoginEvent($user, true); } } return $this->user = $user; }