You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Laravel Sanctum生成刷新令牌及替换过期令牌

Laravel Sanctum 生成刷新令牌及令牌刷新方案

Laravel Sanctum 默认的 API 令牌没有内置刷新机制,需要我们自定义实现一套刷新令牌逻辑,以下是具体方案:

一、创建刷新令牌存储表

首先生成迁移文件来存储刷新令牌:

php artisan make:migration create_refresh_tokens_table

编辑迁移文件,添加必要字段:

public function up()
{
    Schema::create('refresh_tokens', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->onDelete('cascade');
        $table->foreignId('access_token_id')->constrained('personal_access_tokens')->onDelete('cascade');
        $table->string('token')->unique();
        $table->timestamp('expires_at');
        $table->timestamps();
    });
}

执行迁移:

php artisan migrate

二、定义模型与关联

创建 RefreshToken 模型:

php artisan make:model RefreshToken

在模型中设置关联和可填充字段:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class RefreshToken extends Model
{
    protected $fillable = ['user_id', 'access_token_id', 'token', 'expires_at'];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function accessToken(): BelongsTo
    {
        return $this->belongsTo(PersonalAccessToken::class);
    }
}

在 User 模型中添加刷新令牌关联:

public function refreshTokens()
{
    return $this->hasMany(RefreshToken::class);
}

三、登录时同时生成访问令牌与刷新令牌

在登录接口中,验证用户凭据后,生成 Sanctum 访问令牌的同时创建对应的刷新令牌:

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use App\Models\RefreshToken;

public function login(Request $request)
{
    $validated = $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if (!Auth::attempt($validated)) {
        return response()->json(['message' => '无效登录凭据'], 401);
    }

    $user = Auth::user();
    // 生成1小时过期的访问令牌
    $accessToken = $user->createToken('auth_token', expiresAt: now()->addHour());
    
    // 生成刷新令牌并哈希存储(仅返回明文一次给前端)
    $refreshTokenPlain = Str::random(64);
    RefreshToken::create([
        'user_id' => $user->id,
        'access_token_id' => $accessToken->accessToken->id,
        'token' => hash('sha256', $refreshTokenPlain),
        'expires_at' => now()->addDays(7), // 刷新令牌有效期设为7天
    ]);

    return response()->json([
        'access_token' => $accessToken->plainTextToken,
        'refresh_token' => $refreshTokenPlain,
        'token_type' => 'Bearer',
        'expires_at' => $accessToken->accessToken->expires_at->toDateTimeString(),
    ]);
}

四、使用刷新令牌获取新访问令牌

创建刷新接口,验证刷新令牌的有效性后生成新的访问令牌:

use Illuminate\Support\Facades\Hash;
use App\Models\RefreshToken;

public function refresh(Request $request)
{
    $validated = $request->validate([
        'refresh_token' => 'required|string',
    ]);

    $hashedToken = hash('sha256', $validated['refresh_token']);
    $refreshToken = RefreshToken::where('token', $hashedToken)->first();

    // 检查刷新令牌是否存在或已过期
    if (!$refreshToken || $refreshToken->expires_at->isPast()) {
        return response()->json(['message' => '刷新令牌无效或已过期'], 401);
    }

    $user = $refreshToken->user;
    // 注销旧的访问令牌
    $refreshToken->accessToken->delete();
    
    // 生成新的访问令牌
    $newAccessToken = $user->createToken('auth_token', expiresAt: now()->addHour());
    
    // 更新刷新令牌为新的(也可选择生成全新的刷新令牌)
    $newRefreshTokenPlain = Str::random(64);
    $refreshToken->update([
        'token' => hash('sha256', $newRefreshTokenPlain),
        'access_token_id' => $newAccessToken->accessToken->id,
        'expires_at' => now()->addDays(7),
    ]);

    return response()->json([
        'access_token' => $newAccessToken->plainTextToken,
        'refresh_token' => $newRefreshTokenPlain,
        'token_type' => 'Bearer',
        'expires_at' => $newAccessToken->accessToken->expires_at->toDateTimeString(),
    ]);
}

五、路由配置

在 routes/api.php 中添加对应的路由:

use App\Http\Controllers\AuthController;

Route::post('/login', [AuthController::class, 'login']);
Route::post('/refresh', [AuthController::class, 'refresh']);

六、关键注意事项

  • 刷新令牌建议存储在HttpOnly、Secure Cookie中,避免XSS攻击窃取
  • 始终哈希存储刷新令牌,数据库中不要保留明文
  • 可添加刷新令牌的单次使用限制(验证后立即失效,生成新的),提升安全性
  • 提供注销接口,允许用户删除所有关联的访问令牌和刷新令牌

内容的提问来源于stack exchange,提问作者user14773037

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:36:00