如何构建私有服务端到客户端API?Laravel Passport配置及Token获取疑问
看起来你遇到的核心问题有三个:想让Axios能调用API但禁止浏览器直接访问、允许访客用户调用部分API,还有搞不清用户该如何获取Token以及解决未授权报错。我来一步步帮你梳理清楚:
1. 允许访客用户调用API(解决未授权报错)
如果你希望访客(未登录用户)能访问某个API接口,不要给这个路由加上认证中间件。比如你原来的路由可能是这样的:
Route::get('/api/user', [UserController::class, 'show'])->middleware('auth:sanctum');
把中间件去掉,改成:
Route::get('/api/user', [UserController::class, 'show']);
这样访客就能直接访问这个接口,不会返回Unauthorized了。如果只是部分接口允许访客访问,其他需要登录,就给需要登录的接口单独加认证中间件即可。
2. 禁止浏览器直接访问,只允许Axios调用
要实现这个,我们可以通过检查请求的特征来判断是不是Axios发起的请求。Axios默认会带上X-Requested-With: XMLHttpRequest请求头,同时通常请求的Accept头是application/json。我们可以自定义一个中间件来做这个判断:
步骤1:创建中间件
运行Artisan命令:
php artisan make:middleware AllowOnlyAjaxRequests
然后在app/Http/Middleware/AllowOnlyAjaxRequests.php里修改逻辑:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class AllowOnlyAjaxRequests { public function handle(Request $request, Closure $next): Response { // 检查是否是AJAX请求,且接受JSON响应 if (!$request->ajax() && !$request->wantsJson()) { abort(403, 'Direct access not allowed'); } return $next($request); } }
步骤2:注册中间件
在app/Http/Kernel.php的$routeMiddleware里添加:
'ajax.only' => \App\Http\Middleware\AllowOnlyAjaxRequests::class,
步骤3:给路由加上这个中间件
现在把需要限制的路由加上这个中间件:
Route::get('/api/user', [UserController::class, 'show'])->middleware('ajax.only');
这样当用户直接在浏览器输入domain.test/api/user时,会返回403禁止访问,但Axios调用时因为带有正确的请求头,就能正常获取数据。
3. 登录用户的Token获取与使用
如果你需要登录用户才能访问某些接口(比如获取个人专属信息),那需要用Laravel的认证机制,比如Sanctum:
方式一:SPA场景(前后端同域)
如果你的前端和后端是同域的,直接用Sanctum的SPA认证即可:
- 先在
config/cors.php里配置允许的域名,确保supports_credentials设为true - 前端Axios要开启
withCredentials: true,这样会自动携带认证cookie,不需要手动管理Token - 登录接口用Laravel默认的
login路由,登录成功后,后续的API请求就会自动带上认证信息,不需要手动加Token头
方式二:分离式前后端(跨域)
如果前后端是完全分离的,需要手动获取和携带Token:
- 创建登录接口:写一个接口接收用户名和密码,验证成功后生成API Token并返回:
use Illuminate\Support\Facades\Auth; Route::post('/api/login', function () { $credentials = request(['email', 'password']); if (!Auth::attempt($credentials)) { return response()->json(['message' => 'Invalid credentials'], 401); } $user = Auth::user(); $token = $user->createToken('API Token')->plainTextToken; return response()->json(['token' => $token, 'user' => $user]); });
- 前端保存Token:Axios调用登录接口后,把返回的
token存在localStorage或者sessionStorage里 - 请求时携带Token:在Axios的请求拦截器里加上Authorization头:
axios.interceptors.request.use(config => { const token = localStorage.getItem('api_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; });
这样登录用户就能正常访问带auth:sanctum中间件的接口了。
最后再检查几个关键点
- 确保你的CORS配置正确,特别是跨域请求时要允许相关请求头
- 如果用Sanctum,记得在
config/sanctum.php里配置stateful域名 - 测试的时候,用Postman或者Axios发起请求,看看请求头是否正确携带
内容的提问来源于stack exchange,提问作者Philipp Mochine

