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

上面说到AuthManager创建了guard,然后调用check(),我先现在来分析下Guard。还是那句话,不管上层业务代码多么复杂,底层的接口往往是很简单的。Lumen/Laravel框架中大部分接口被设计成是一种契约(Contracts),Guard也一样的,它的代码在\vendor\illuminate\contracts\Auth\Guard.php文件中,只有6个方法

// \Illuminate\Contracts\Auth\Guard.php namespace Illuminate\Contracts\Auth; interface Guard { // 判断当前用户是否登录 public function check(); // 判断当前用户是否是游客(未登录) public function guest(); // 获取当前认证的用户 public function user(); // 获取当前认证用户的 id,严格来说不一定是 id,应该是这个模型中的主键字段 public function id(); // 用户验证 public function validate(array $credentials = []); // 设置当前认证过的用户 public function setUser(Authenticatable $user); }

很简单,有木有~同样,还有一个StatefulGuard接口,继承自Guard接口并加了几个有状态的方法,代表有状态,就是每次请求都带有用户的状态信息比如session,代码如下:

// Illuminate\Contracts\Auth\StatefulGuard.php namespace Illuminate\Contracts\Auth; interface StatefulGuard extends Guard { // 指定数据验证 public function attempt(array $credentials = [], $remember = false); // 将这一次request验证通过登录,不会保存session/cookie public function once(array $credentials = []); // 登录 public function login(Authenticatable $user, $remember = false); // 使用id登录 public function loginUsingId($id, $remember = false); // 和once()一样,不过是用id public function onceUsingId($id); // 通过remember cookie登录 public function viaRemember(); // 注销 public function logout(); }

UML图大致如下:

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

6. Guard接口的相关实现

底层接口着实简单,再来分析下上层的实现代码,框架中默认实现了几个Guard,比如Web开发用到的SessionGuard,接口开发用到的TokenGuard,这些都实现自\Illuminate\Contracts\Auth或者\Illuminate\Contracts\Auth\StatefulGuard,已经满足我们日常所需了。

几个Guard的check()方法都是一样的,都定义在GuardHelpers这个Trait中:

// \Illuminate\Auth\GuardHelpers.php /** * Determine if the current user is authenticated. * * @return bool */ public function check() { return ! is_null($this->user()); }

user()就是在不同的Guard中实现了,后面也主要看这个方法。

GuardHelpers Trait

什么是Trait:

你可以理解成一系列方法的集合,就是把经常使用到的重复方法整合起来,在class里面直接use使用,上下文还是引用它的那个class,减少了重复代码量,而且比class更轻量,不需要new在使用。

6.1 RequestGuard.php

RequestGuard认证一个http请求,具体怎么认证,它是通过callback实现的,认证逻辑在callback中直接放到了上层让用户自定义,UML图:

RequestGuard

看代码实现也很简单:

// \Illuminate\Auth\RequestGuard.php /** * 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; } return $this->user = call_user_func( $this->callback, $this->request, $this->getProvider() ); }

RequestGuard很多文章都是一笔带过,这【公众号)里我说(正义的程序猿)一下,通常我们使用不到RequestGuard,只有在自定义Guard时才用得上。

使用方式如下

AuthServiceProvider中注册自定义的guard,设置名称和callback:

// App\Providers\AuthServiceProvider.php use App\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; /** * Register any application authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); Auth::viaRequest('custom-token', function ($request) { return User::where('my-token', $request->my_token)->first(); }); }

auth.php中配置自定义guard

'guards' => [ 'my-api' => [ 'driver' => 'custom-token', ], ],

使用

还是上面的例子:

Route::get('/user/profile', 'UserController@profile')->middleware('auth:my-api');

最后在认证的时候就会直接使用我们设置的callback了。

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

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