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

上面viaRequest()也是定义AuthManager中:

// \Illuminate\Auth\AuthManager.php /** * Register a new callback based request guard. * * @param string $driver * @param callable $callback * @return $this */ public function viaRequest($driver, callable $callback) { return $this->extend($driver, function () use ($callback) { $guard = new RequestGuard($callback, $this->app['request'], $this->createUserProvider()); $this->app->refresh('request', $guard, 'setRequest'); return $guard; }); } 6.2 SessionGuard

见名知义,此guard是基于session的,一般最常用的就是(公众号:)这(正义的程序猿)个了。由于是基于session所以是有状态的,所以这个类定义的时候实现了StatefulGuard接口,而且加了更多逻辑代码和注释加起来有800+行,

// \Illuminate\Auth\SessionGuard.php namespace Illuminate\Auth; use Illuminate\Contracts\Auth\StatefulGuard; use Illuminate\Contracts\Auth\SupportsBasicAuth; class SessionGuard implements StatefulGuard, SupportsBasicAuth { ... }

UML图:

SessionGuard

用户认证的代码稍微复杂一点,如下:

// \Illuminate\Auth\SessionGuard.php /** * Get the currently authenticated user. * * @return \Illuminate\Contracts\Auth\Authenticatable|null */ 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()); // 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. if (! is_null($id) && $this->user = $this->provider->retrieveById($id)) { $this->fireAuthenticatedEvent($this->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. if (is_null($this->user) && ! is_null($recaller = $this->recaller())) { $this->user = $this->userFromRecaller($recaller); if ($this->user) { $this->updateSession($this->user->getAuthIdentifier()); $this->fireLoginEvent($this->user, true); } } return $this->user; }

梳理下,大致是先从session获取用户的主键id,然后通过特定的UserProvider查找用户,查找成功说明验证成功,如果没有,就用recaller查询用户,这里就是remember token查找,就是登录时“记住我”的那个选项,remember token是保存在cookie当中的,如果remember token查找成功,就说明验证成功,否则验证失败。

6.3 TokenGuard

TokenGuard也实现了Guard接口,适用于无状态的api认证,UML图:

TokenGuard

由于不要维护状态整个代码就简单很多:

// \Illuminate\Auth\TokenGuard.php namespace Illuminate\Auth; use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\UserProvider; use Illuminate\Http\Request; class TokenGuard implements Guard { ... /** * Get the currently authenticated user. * * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function user() { // 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; } $user = null; $token = $this->getTokenForRequest(); if (! empty($token)) { $user = $this->provider->retrieveByCredentials([ $this->storageKey => $this->hash ? hash('sha256', $token) : $token, ]); } return $this->user = $user; } ... }

先从请求中获取api_token,再用api_token从指定的UserProvider查找api_token对应的用户信息。

至此,Laravel中Guard相关的分析已经差不多了,通过分析它的源码,我们深入了解了框架背后的思想,梳理的过程也是学习的过程,对新手而言能快速掌握guard的相关知识并快速上手,对老鸟而言,我觉得这篇文章写的已经很细了,能更好地了解框架背后的精髓写出更优雅的代码。

总结

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

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