如何禁止访问Laravel默认oauth/token接口,仅使用自定义令牌函数?
嘿,这个需求很实用,毕竟我们希望令牌发放逻辑完全由自定义函数控制,避免用户绕过业务规则直接调用默认接口。下面给你几个可行的方案,你可以根据自己的Laravel版本和业务复杂度选择:
方案1:直接覆盖默认路由(最简单)
Laravel Passport的oauth/token路由是默认注册的,我们可以在routes/api.php里重新定义这个路由,让它返回拒绝访问的响应,直接拦截所有对该接口的请求:
// 在routes/api.php中添加 Route::post('/oauth/token', function () { return response()->json([ 'message' => '请通过指定的自定义接口获取访问令牌' ], 403); });
注意:这个方案的前提是你的自定义令牌接口使用独立路由(比如
/api/custom-token),而非复用默认的oauth/token。这样用户访问默认接口会得到403,只能走自定义逻辑。
方案2:用中间件限制访问(灵活可控)
如果需要更灵活的控制(比如允许特定内部服务访问,拒绝外部直接请求),可以给oauth/token路由添加自定义中间件,检查请求合法性:
步骤1:创建中间件
php artisan make:middleware RestrictOauthTokenAccess
步骤2:编写中间件逻辑
打开app/Http/Middleware/RestrictOauthTokenAccess.php,在handle方法里添加验证规则,比如检查请求头里的自定义标识:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; class RestrictOauthTokenAccess { public function handle(Request $request, Closure $next) { // 检查请求是否来自自定义函数,验证特定请求头 if (!$request->hasHeader('X-Allow-Token-Request')) { return response()->json([ 'message' => '禁止直接访问该令牌接口' ], 403); } // 可选:验证请求头的值是否匹配预设密钥,提升安全性 if ($request->header('X-Allow-Token-Request') !== config('app.custom_token_secret')) { return response()->json([ 'message' => '非法请求' ], 403); } return $next($request); } }
步骤3:注册中间件
打开app/Http/Kernel.php,在$routeMiddleware数组里添加:
protected $routeMiddleware = [ // ... 其他中间件 'restrict.oauth.token' => \App\Http\Middleware\RestrictOauthTokenAccess::class, ];
步骤4:给Passport路由添加中间件
在app/Providers/AuthServiceProvider.php的boot方法里,修改Passport路由注册逻辑,给令牌路由加上中间件:
use Laravel\Passport\Passport; public function boot() { $this->registerPolicies(); // 自定义Passport路由,添加中间件 Passport::routes(function ($router) { $router->forAccessTokens()->middleware('restrict.oauth.token'); // 其他Passport路由(如授权码、刷新令牌)可按需处理 }); }
这样,只有自定义函数请求时带上正确的X-Allow-Token-Request头,才能通过中间件访问oauth/token,外部直接请求会被拒绝。
方案3:自定义Passport授权Grant(最底层控制)
如果需要完全替换默认的密码授权流程,可以自定义Grant类,替换Passport默认的密码授权器,这样即使有人调用oauth/token,也无法触发默认令牌生成逻辑:
步骤1:创建自定义Grant类
<?php namespace App\Passport\Grants; use Laravel\Passport\Bridge\PasswordGrant; use League\OAuth2\Server\RequestEvent; use Psr\Http\Message\ServerRequestInterface; class CustomPasswordGrant extends PasswordGrant { /** * 验证请求合法性,添加自定义规则 */ protected function validateUser(ServerRequestInterface $request) { // 示例:仅允许携带特定标识的请求生成令牌 $customFlag = $request->getParsedBody()['custom_flag'] ?? null; if (!$customFlag || $customFlag !== 'allow_custom_token') { $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request)); throw new \League\OAuth2\Server\Exception\OAuthServerException('Invalid request', 403, 'invalid_request'); } // 调用父类逻辑完成用户名密码等基础验证 return parent::validateUser($request); } }
步骤2:替换默认的Grant
在app/Providers/AuthServiceProvider.php的boot方法里,替换Passport的默认密码授权器:
use Laravel\Passport\Bridge\PasswordGrant; use Laravel\Passport\Passport; use League\OAuth2\Server\AuthorizationServer; use App\Passport\Grants\CustomPasswordGrant; public function boot() { $this->registerPolicies(); Passport::routes(); // 替换默认的密码授权Grant $this->app->extend(AuthorizationServer::class, function ($server, $app) { // 移除默认的密码授权Grant $server->disableGrantType(PasswordGrant::IDENTIFIER); // 添加自定义Grant $grant = new CustomPasswordGrant( $app->make(\Laravel\Passport\Bridge\UserRepository::class), $app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class) ); $grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn()); $server->enableGrantType( $grant, Passport::tokensExpireIn() ); return $server; }); }
这样,用户直接调用oauth/token时因未携带custom_flag参数会被拒绝,只有自定义函数携带该参数才能正常生成令牌。
内容的提问来源于stack exchange,提问作者aishazafar

