Laravel Passport
简介
Laravel Passport 可以在几分钟之内为你的应用程序提供完整的 OAuth2 服务端实现。Passport 是基于由 Andy Millington 和 Simon Hamp 维护的 League OAuth2 server 建立的。
本文档假定你已熟悉 OAuth2 。如果你并不了解 OAuth2 ,阅读之前请先熟悉下 OAuth2 的 常用术语 和特性。
Passport 还是 Sanctum?
在开始之前,我们希望你先确认下是 Laravel Passport 还是 Laravel Sanctum 能为你的应用提供更好的服务。如果你的应用确确实实需要支持 OAuth2,那没疑问,你需要选用 Laravel Passport。
然而,如果你只是试图要去认证一个单页应用,或者手机应用,或者发布 API 令牌,你应该选用 Laravel Sanctum。 Laravel Sanctum 不支持 OAuth2,它提供了更为简单的 API 授权开发体验。
安装
在开始使用之前,使用 Composer 包管理器安装 Passport:
composer require laravel/passport
Passport 的 服务提供器 注册了自己的数据库迁移脚本目录, 所以你应该在安装软件包完成后迁移你自己的数据库。 Passport 的迁移脚本将为你的应用创建用于存储 OAuth2 客户端和访问令牌的数据表:
php artisan migrate
接下来,你需要执行 Artisan 命令 passport:install
。这个命令将会创建一个用于生成安全访问令牌的加密秘钥。另外,这个命令也将创建用于生成访问令牌的 「个人访问」 客户端和 「密码授权」 客户端 :
php artisan passport:install
如果你想用使用 UUID 作为 Passport Client
模型的主键,代替默认的自动增长整形字段,请在安装 Passport 时使用 uuids 参数 。
在执行 passport:install
命令后, 添加 Laravel\Passport\HasApiTokens
trait 到你的 App\Models\User
模型中。 这个 trait 会提供一些帮助方法用于检查已认证用户的令牌 和权限范围。如果你的模型已经在使用 Laravel\Sanctum\HasApiTokens
trait,你可以删除该 trait:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
最后,在您的应用的 config/auth.php
配置文件中,您应当定义一个 api
的授权看守器,并且将其 driver
选项设置为 passport
。这个调整将会让您的应用程序使用 Passport 的 TokenGuard
来鉴权 API 接口请求:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
客户端 UUID
您也可以在运行 passport:install
命令的时候使用 --uuids
选项。这个参数将会让 Passport 使用 UUID 来替代默认的自增长形式的 Passport Client
模型主键。在您运行带有 --uuids
参数的 passport:install
命令后,您将得到关于禁用 Passport 默认迁移的相关指令说明:
php artisan passport:install --uuids
部署 Passport
在您第一次部署 Passport 到您的应用服务器时,您需要执行 passport:keys
命令。该命令用于生成 Passport 用于生成 access token 的一 个加密密钥。生成的加密密钥不应到添加到源代码控制系统中:
php artisan passport:keys
如有必要,您可以定义 Passport 的密钥应当加载的位置。您可以使用 Passport:loadKeysFrom
方法来实现。通常,这个方法应当在您的 App\Providers\AuthServiceProvider
类的 boot
方法中调用:
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
Passport::loadKeysFrom(__DIR__.'/../secrets/oauth');
}
从环境中加载密钥
此外,您可以使用 vendor:publish
Artisan 命令来发布您的 Passport 配置文件:
php artisan vendor:publish --tag=passport-config
在发布配置文件之后,您可以将加密密钥配置为环境变量,再加载它们:
PASSPORT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
<private key here>
-----END RSA PRIVATE KEY-----"
PASSPORT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
<public key here>
-----END PUBLIC KEY-----"
自定义迁移
如果您不打算使用 Passport 的默认迁移,您应当在 App\Providers\AppServiceProvider
类的 register
方法中调用 Passport::ignoreMigrations
方法。您可以 使用 vendor:publish
Artisan 命令来导出默认的迁移文件:
php artisan vendor:publish --tag=passport-migrations
Passport 的升级
当升级到 Passport 的主要版本时,请务必查阅 升级指南.
配置
客户端密钥的 Hash 加密
如果您希望客户端密钥在存储到数据库时使用 Hash 对其进行加密,您应当在 App\Provider\AuthServiceProvider
类的 boot
方法中调用 Passport:hashClientSecrets
:
use Laravel\Passport\Passport;
Passport::hashClientSecrets();
一旦启用后,所有的客户端密钥都将只在创建的时候显示。由于明文的客户端密钥没有存储到数据库中,因此一旦其丢失后便无法恢复。
Token 生命周期
默认情况下,Passport 会颁发长达一年的长期 token 。如果您想要配置一个更长或更短的 token 生命周期,您可以在 App\Provider\AuthServiceProvider
类的 boot
方法中调用 tokensExpiresIn
、refresgTokensExpireIn
和 personalAccessTokensExpireIn
方法:
/**
* 注册身份验证/授权服务。
*/
public function boot(): void
{
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}
Passport 数据库表中的 expires_at
列是只读的,仅仅用于显示。在颁发 token 的时候,Passport 将过期信息存储在已签名和加密的 token 中。如果你想让 token 失效,你应当 撤销它 。
重写 Passport 的默认模型
您可以通过定义自己的模型并继承相应的 Passport 模型来实现自由自由扩展 Passport 内部使用的模型:
use Laravel\Passport\Client as PassportClient;
class Client extends PassportClient
{
// ...
}
在定义您的模型之后,您可以在 Laravel\Passport\Passport
类中指定 Passport 使用您自定义的模型。一样的,您应该在应用程序的 App\Providers\AuthServiceProvider
类中的 boot
方法中指定 Passport 使用您自定义的模型:
use App\Models\Passport\AuthCode;
use App\Models\Passport\Client;
use App\Models\Passport\PersonalAccessClient;
use App\Models\Passport\RefreshToken;
use App\Models\Passport\Token;
/**
* 注册任意认证/授权服务。
*/
public function boot(): void
{
Passport::useTokenModel(Token::class);
Passport::useRefreshTokenModel(RefreshToken::class);
Passport::useAuthCodeModel(AuthCode::class);
Passport::useClientModel(Client::class);
Passport::usePersonalAccessClientModel(PersonalAccessClient::class);
}
重写路由
您可能希望自定义 Passport 定义的路由。要实现这个功能,第一步,您需要在应用程序的 AppServiceProvider
中的 register
方法中添加 Passport:ignoreRoutes
语句,以忽略由 Passport 注册的路由:
use Laravel\Passport\Passport;
/**
* 注册任意的应用程序服务。
*/
public function register(): void
{
Passport::ignoreRoutes();
}
然后,您可以复制 Passport 在自己的文件中 定义的路由到应用程序的 routes/web.php
文件中,并且将其修改为您喜欢的任何形式:
Route::group([
'as' => 'passport.',
'prefix' => config('passport.path', 'oauth'),
'namespace' => 'Laravel\Passport\Http\Controllers',
], function () {
// Passport 路由……
});
发布访问令牌
通过授权码使用 OAuth2 是大多数开发人员熟悉的方式。使用授权码方式时,客户端应用程序会将用户重定向到你的服务器,在那里他们会批准或拒绝向客户端发出访问令牌的请求。
客户端管理
首先,开发者如果想要搭建一个与你的服务端接口交互的应用端,需要在服务端这边注册一个「客户端」。通常,这需要开发者提供应用程序的名称和一个 URL,在应用软件的使用者授权请求后,应用程序会被重定向到该 URL。
passport:client
命令
使用 Artisan 命令 passport:client
是一种最简单的创建客户端的方式。 这个命令可以创建你自己私有的客户端,用于 Oauth2 功能测试。 当你执行 client
命令后, Passport 将会给你更多关于客户端的提示,以及生成的客户端 ID
php artisan passport:client
多重定向 URL 地址的设置
如果你想为你的客户端提供多个重定向 URL ,你可以在执行 Passport:client
命令出现提示输入 URL 地址的时候,输入用逗号分割的多个 URL 。任何包含逗号的 URL 都需要先执行 URL 转码:
http://example.com/callback,http://examplefoo.com/callback
JSON API
因为应用程序的开发者是无法使用 client
命令的,所以 Passport 提供了 JSON 格式的 API ,用于创建客户端。 这解决了你还要去手动创建控制器代码(代码用于添加,更新,删除客户端)的麻烦。
但是,你需要结合 Passport 的 JSON API 接口和你的前端面板管理页面, 为你的用户提供客户端管理功能。接下里,我们会回顾所有用于管理客户端的的 API 接口。方便起见,我们使用 Axios 模拟对端点的 HTTP 请求。
这些 JSON API 接口被 web
和 auth
两个中间件保护着,因此,你只能从你的应用中调用。 外部来源的调用是被禁止的。
GET /oauth/clients
下面的路由将为授权用户返回所有的客户端。最主要的作用是列出所有的用户客户端,接下来就可以编辑或删除它们了:
axios.get('/oauth/clients')
.then(response => {
console.log(response.data);
});