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

如何在前端应用中正确使用Laravel Sanctum令牌?

解决方案:Laravel Sanctum 单应用 API 复用与权限验证优化

你的核心问题在于硬编码令牌无法适配多用户场景,且通过 HTTP 调用自身 API 存在冗余开销。以下是针对你的场景的几种可行方案,按推荐优先级排序:


方案一:直接复用业务逻辑(最优)

既然是同一个应用,完全没必要通过 HTTP 请求调用自身 API,抽离共享逻辑到服务层即可实现复用,同时避免令牌传递的麻烦。

步骤1:封装共享业务逻辑到服务类

创建服务类统一处理产品查询与权限验证:

namespace App\Services;

use App\Models\User;
use App\Models\Product;
use Illuminate\Http\Exceptions\HttpResponseException;

class ProductService
{
    public function getProducts(User $user)
    {
        // 验证用户令牌权限(管理员分配令牌时需指定对应abilities)
        if (!$user->tokenCan('view:products')) {
            throw new HttpResponseException(response()->json([
                'message' => '无产品查看权限'
            ], 403));
        }

        return Product::query()->get();
    }
}

步骤2:API 控制器调用服务类

namespace App\Http\Controllers\Api\V1;

use App\Services\ProductService;
use Illuminate\Http\Request;

class ProductsController extends Controller
{
    public function index(Request $request, ProductService $service)
    {
        $products = $service->getProducts($request->user());
        return response()->json($products);
    }
}

步骤3:前端控制器直接调用服务类

namespace App\Http\Controllers;

use App\Services\ProductService;
use Illuminate\Support\Facades\Auth;

class ProductViewController extends Controller
{
    // 确保路由已添加 auth 中间件,限制仅登录用户访问
    public function index(ProductService $service)
    {
        $user = Auth::user();
        $products = $service->getProducts($user);
        
        return view('products', ['products' => $products]);
    }
}

方案二:通过 Sanctum 会话认证调用自身 API

如果坚持要通过 HTTP 调用 API,可利用 Sanctum 的会话认证能力,无需手动传递令牌:

1. 配置 Sanctum 信任域名

在 config/sanctum.php 中添加自身域名到 stateful 数组:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

2. 修改前端控制器代码

当前用户通过 Web 登录后,Sanctum 会自动维护会话认证状态,调用 API 时无需手动携带令牌:

public function index()
{
    // 路由需添加 auth 中间件,确保用户已登录
    $products = Http::get(env('APP_URL').'/api/v1/products');
    
    return view('products', ['products' => $products->json()]);
}

3. API 路由保持原有配置

确保 API 路由使用 auth:sanctum 中间件,同时兼容外部令牌调用与内部会话认证:

Route::middleware('auth:sanctum')->group(function () {
    Route::get('/api/v1/products', [\App\Http\Controllers\Api\V1\ProductsController::class, 'index']);
});

方案三:手动传递用户令牌(仅特殊场景使用)

如果必须手动传递令牌,需注意:数据库中存储的令牌是哈希值,无法直接读取,必须在创建令牌时保存原始令牌值(建议加密存储)。

1. 创建令牌时保存原始值

管理员分配令牌时,将生成的原始令牌加密后存入用户表(需先给用户表添加 api_token 字段):

// 管理员创建用户令牌示例
$token = $user->createToken('产品访问令牌', ['view:products'])->plainTextToken;
$user->update(['api_token' => encrypt($token)]);

2. 前端控制器获取并使用令牌

public function index()
{
    $user = Auth::user();
    // 解密获取原始令牌
    $token = decrypt($user->api_token);
    
    $products = Http::withToken($token)
        ->get(env('APP_URL').'/api/v1/products');
    
    return view('products', ['products' => $products->json()]);
}

注意:此方案存在安全风险,令牌值存储在数据库中(即使加密),不如会话认证安全,仅在特殊场景下使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:10:20