如何实现Laravel API与Laravel APP的Token-域名绑定鉴权?
实现Laravel API的Token与请求域名绑定鉴权
1. 扩展Token存储结构
首先需要在存储Token的表中添加域名绑定字段,以Laravel自带的**个人访问令牌(Personal Access Tokens)**为例:
- 生成迁移文件:
php artisan make:migration add_domain_to_personal_access_tokens_table
- 编辑迁移文件,添加
domain字段:
public function up() { Schema::table('personal_access_tokens', function (Blueprint $table) { $table->string('domain')->nullable()->after('token'); }); } public function down() { Schema::table('personal_access_tokens', function (Blueprint $table) { $table->dropColumn('domain'); }); }
- 执行迁移:
php artisan migrate
如果使用自定义Token管理表,同理添加domain字段即可。
2. 修改Token生成逻辑(创建账号/分配Token时)
在创建账号并分配Token的逻辑中,收集用户输入的来源Web URL,解析出域名后绑定到Token上:
use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; // 示例:创建账号并生成绑定域名的Token public function createAccount(Request $request) { // 验证输入参数 $request->validate([ 'name' => 'required|string', 'email' => 'required|email|unique:users', 'source_url' => 'required|url', 'password' => 'required|string|min:8', ]); // 解析URL,提取纯域名(如laravel-app-1.test) $domain = parse_url($request->source_url, PHP_URL_HOST); // 创建用户 $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); // 生成Token并绑定域名 $tokenResult = $user->createToken('api-token', [], now()->addYears(1)); $plainToken = $tokenResult->plainTextToken; // 更新Token记录的domain字段 $user->tokens()->latest()->update(['domain' => $domain]); return response()->json([ 'token' => $plainToken, 'bound_domain' => $domain, 'message' => '账号创建成功,Token已绑定指定域名' ]); }
3. 编写自定义鉴权中间件
创建中间件验证Token对应的域名与请求来源域名是否匹配:
- 生成中间件:
php artisan make:middleware VerifyTokenDomain
- 编辑中间件逻辑:
use Closure; use Illuminate\Http\Request; use Laravel\Sanctum\PersonalAccessToken; class VerifyTokenDomain { public function handle(Request $request, Closure $next) { // 获取请求携带的Token $token = $request->bearerToken(); if (!$token) { return response()->json(['message' => '未授权'], 401); } // 查询Token记录 $accessToken = PersonalAccessToken::findToken($token); if (!$accessToken || !$accessToken->tokenable) { return response()->json(['message' => '无效的Token'], 401); } // 提取请求来源域名(优先取Origin头,其次取Referer) $requestDomain = null; if ($request->hasHeader('Origin')) { $requestDomain = parse_url($request->header('Origin'), PHP_URL_HOST); } elseif ($request->hasHeader('Referer')) { $requestDomain = parse_url($request->header('Referer'), PHP_URL_HOST); } // 验证域名匹配 if (!$requestDomain || $requestDomain !== $accessToken->domain) { return response()->json(['message' => 'Token与请求域名不匹配,拒绝访问'], 401); } return $next($request); } }
4. 注册并启用中间件
- 在
app/Http/Kernel.php的$routeMiddleware数组中注册中间件:
protected $routeMiddleware = [ // 其他中间件... 'token.domain' => \App\Http\Middleware\VerifyTokenDomain::class, ];
- 将中间件添加到API路由组(
routes/api.php):
Route::middleware(['auth:sanctum', 'token.domain'])->group(function () { // 你的API路由 Route::get('/user', function (Request $request) { return $request->user(); }); // 其他需要验证的路由... });
5. 关键注意事项
- 域名解析处理:确保解析来源URL和请求头时只提取纯域名,过滤协议、端口等多余内容。
- 无来源头场景:若请求无Origin/Referer头,可根据业务需求返回错误,或允许内部服务等特定场景的访问。
- Token管理:可新增接口支持用户更新Token绑定的域名,提升灵活性。
- 测试验证:用不同域名的客户端请求API,验证只有绑定域名的请求能正常访问,其他域名返回401。
内容的提问来源于stack exchange,提问作者kvb4
相关产品推荐
相关产品推荐

