Laravel Sanctum API 授权

2023-04-16 16:28:31 浏览数 (1)

Laravel Sanctum 为 SPA(单页应用程序)、移动应用程序和基于令牌的、简单的 API 提供轻量级身份验证系统。Sanctum 允许应用程序的每个用户为他们的帐户生成多个 API 令牌。这些令牌可以被授予指定允许令牌执行哪些操作的能力 / 范围。

简单来说,前后端分离的项目,使用 token 验证登陆状态,可以选它;另外,同类型的还有 jwt 比较火

安装

Laravel 9 已经包含了 Laravel Sanctum,所以下面的步骤看看就行了

代码语言:javascript复制
composer require laravel/sanctum
php artisan vendor:publish --provider="LaravelSanctumSanctumServiceProvider"
php artisan migrate

接下来,如果您想利用 Sanctum 对 SPA 进行身份验证,您应该将 Sanctum 的中间件添加到您应用的 app/Http/Kernel.php 文件中的 api 中间件组中:

代码语言:javascript复制
'api' => [
    LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    IlluminateRoutingMiddlewareSubstituteBindings::class,
],

注意,EnsureFrontendRequestsAreStateful 这一行,Laravel 9默认是注释掉的,需要取消注释

API 令牌认证

发布 API Tokens

要开始为用户颁发令牌,你的 User 模型应使用 LaravelSanctumHasApiTokens trait:

代码语言:javascript复制
use LaravelSanctumHasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

Laravel 9已经默认添加了

要发布令牌,你可以使用 createToken 方法。 createToken 方法返回一个 LaravelSanctumNewAccessToken 实例。 在存入数据库之前,API 令牌已使用 SHA-256 哈希加密过,但你可以使用 NewAccessToken 实例的 plainTextToken 属性访问令牌的纯文本值。创建令牌后,你应该立即向用户显示此值:

代码语言:javascript复制
$token = $request->user()->createToken($request->token_name);
return ['token' => $token->plainTextToken];

你可以使用 HasApiTokens trait 提供的 tokens Eloquent 关系访问用户的所有令牌:

代码语言:javascript复制
foreach ($user->tokens as $token) {
    //
}

令牌能力

Sanctum 允许你将 「能力」分配给令牌。能力的用途与 OAuth 的「Scope」类似。你可以将字符串能力数组作为第二个参数传递给 createToken 方法:

代码语言:javascript复制
return $user->createToken('token-name', ['server:update'])->plainTextToken;

在处理由 Sanctum 验证的传入请求时,你可以使用 tokenCan 方法确定令牌是否具有给定的能力:

代码语言:javascript复制
if ($user->tokenCan('server:update')) {
    //
}

令牌能力中间件

保护路由

代码语言:javascript复制
use IlluminateHttpRequest;

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

撤销令牌

代码语言:javascript复制
// 撤销所有令牌...
$user->tokens()->delete();

// 撤销用于验证当前请求的令牌...
$request->user()->currentAccessToken()->delete();

// 撤销指定令牌...
$user->tokens()->where('id', $tokenId)->delete();

令牌有效期

默认情况下,sanctum 的 token 无过期时限并且仅能通过撤销令牌来使它无效。当然如果您想在您的程序里设置 token 的有效期也是可以的。修改 sanctum 的配置文件中的 expiration 选项(默认为 null),此选项设置的数字表示多少分钟后过期:

代码语言:javascript复制
// 365天后过期
'expiration'  =>  525600,

如果您的程序中配置了 token 的过期时间,那您多半会希望能用任务调度自动删除过期了的 token 数据。有个好消息,sanctum 提供了一个 Artisan 命令,可以实现这个想法:

代码语言:javascript复制
    php artisan sanctum:prune-expired

比如,您可以设置一个调度任务用于删除你数据库中所有过期超过 24 小时的 token 记录:

代码语言:javascript复制
$schedule->command('sanctum:prune-expired --hours=24')->daily();

SPA 认证

这块应该是混合开发模式,再议。。

移动应用身份验证

测试

在测试时,Sanctum::actingAs 方法可用于验证用户并指定为其令牌授予哪些能力:

代码语言:javascript复制
use AppModelsUser;
use LaravelSanctumSanctum;

public function test_task_list_can_be_retrieved()
{
    Sanctum::actingAs(
        User::factory()->create(),
        ['view-tasks']
    );

    $response = $this->get('/api/task');

    $response->assertOk();
}

如果你想授予令牌所有的能力,你应该在提供给 actingAs 方法的能力列表中包含 *:

代码语言:javascript复制
Sanctum::actingAs(
    User::factory()->create(),
    ['*']
);

待解决的问题

token失效后,会报

代码语言:javascript复制
Route [login] not defined.

只有增加header头才会触发授权异常

代码语言:javascript复制
Accept:application/json

参考

https://www.fujuhao.com/posts/laravel-sanctum.html

https://learnku.com/docs/laravel/9.x/sanctum/12272

0 人点赞