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 中间件组中:
'api' => [
LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful::class,
'throttle:api',
IlluminateRoutingMiddlewareSubstituteBindings::class,
],
注意,EnsureFrontendRequestsAreStateful 这一行,Laravel 9默认是注释掉的,需要取消注释
API 令牌认证
发布 API Tokens
要开始为用户颁发令牌,你的 User 模型应使用 LaravelSanctumHasApiTokens
trait:
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