前言
最近需要实现一个功能,需要对接基于 Cookie 的 SSO 方案,用户登录成功后,身份验证中心会在用户的浏览器中设置一个特定域下的 Cookie,用于标识用户的身份。其他需要集成SSO的应用程序在接收到请求时,会检查浏览器中是否存在该特定域下的 Cookie,并使用其中的用户身份信息进行认证和授权。
在 Laravel 框架中默认有提供身份验证(Authentication)服务,并且通过服务容器(Service Container)管理,从而使你能够轻松地替换、扩展和管理。
Laravel 身份验证体系
在开始自定义 Auth Guard 之前,首先需要理解 Laravel 的身份验证体系。Laravel 的身份验证部分已经被抽象出来,它提供了 Guard 和 Provider 的概念来处理用户认证:
- Guard 负责认证请求中的用户,通常与特定的用户身份相关联(例如,通过会话或令牌)。
- Provider 负责从持久化存储(如数据库)中检索用户信息。
Laravel 提供了几个内置的 Guard,包括 Session Guard、Token Guard 和 JWT Guard 等。每个 Guard 都有对应的 Provider,以便获取用户信息。
创建自定义 Guard
要创建自定义 Guard,首先需要创建一个新的 Guard 类并实现Illuminate\Contracts\Auth\Guard
接口。Auth 有提供两个 Guard 接口,分别是 Guard 和 StatefulGuard,顾名思义 StatefulGuard 比 Guard 多了状态能力,因为基于 Cookie 的 SSO 方案,不需要有自己的状态,所以我选择了 Guard 接口去实现。
php
<?php
namespace App\Auth;
use App\Services\SSOService;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Http\Request;
class SSOGuard implements Guard
{
use GuardHelpers;
public function __construct(
private readonly Request $request,
private readonly UserProvider $userProvider
) {
}
public function user()
{
if (!is_null($this->user)) {
return $this->user;
}
$user = null;
$userInfo = SSOService::getUserInfo($this->request->cookie('TOKEN'));
if ($userInfo) {
$this->user = $this->userProvider->retrieveByCredentials(['id' => $user->id]);
}
return $this->user;
}
public function validate(array $credentials = [])
{
// 因为不需要使用 validate 方法所以直接返回 false,如果需要自行补充对应方法内容
return false;
}
}
注册自定义 Guard
接下来需要AppServiceProvider
扩展 Auth Guard:
php
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Auth::extend('sso', function (Application $app, string $name, array $config) {
return new SSOGuard(request(), Auth::createUserProvider($config['provider']));
});
}
}
配置自定义 Guard
在 config/auth.php
文件添加新的guard:
php
'guards' => [
'sso-auth' => [
'driver' => 'sso',
'provider' => 'users',
],
],
使用自定义 Guard
完成了自定义 Guard 的创建、注册、配置,就可以在应用程序中使用它了。可以通过 auth()->guard('sso-auth')
方法来获取自定义 Guard 的实例,并使用其提供的方法进行用户认证和授权。
结论
通过自定义 Laravel 的 Auth Guard,我们能够根据项目需求灵活地定制身份验证和授权功能。特别是将身份验证逻辑写在 Auth Guard 中,能够使代码更加专注和模块化。这样做的好处在于,身份验证逻辑与其他业务逻辑得以分离,从而提高了代码的可维护性和可扩展性。这种分离使得我们能够更清晰地理解和管理身份验证的相关功能,同时也更容易进行测试和调试。