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

Docker中Laravel Passport登录异常:自动加参返回400,手动则正常

Docker环境下Laravel Passport OAuth登录异常排查方案

问题描述

将包含MariaDB数据库、Laravel API和React前端的Web应用容器化为三个独立容器后,使用Laravel Passport实现OAuth用户登录时出现异常:

  • 非Docker环境下认证功能正常运行
  • Docker内部必须手动在请求体中添加client_id、client_secret和grant_type参数才能获得200成功响应
  • 代码中已自动添加上述参数,但自动添加时始终返回400 Bad Request,错误提示如下:
{
  "message": "Authentication has failed!",
  "authentication_server_response": {
    "error": "unsupported_grant_type",
    "error_description": "The authorization grant type is not supported by the authorization server.",
    "hint": "Check that all required parameters have been provided",
    "message": "The authorization grant type is not supported by the authorization server."
  }
}

自动添加参数的代码如下:

public function login($email, $password)
{
    try {
        request()->request->add([
            'grant_type' => 'password',
            'client_id' => config('auth.passport_config.client_id'),
            'client_secret' => config('auth.passport_config.client_secret'),
            'username' => $email,
            'password' => $password,
            'scope'         => '',
        ]);
        $request = Request::create(config('auth.passport_config.server_url') . '/oauth/token', 'POST');
        $response = Route::dispatch($request);
        $errorCode = $response->getStatusCode();
        $auth_server_response = json_decode((string) $response->content(), true);
        if ($errorCode == '200') {
            return [
                "response_body" => $auth_server_response,
                "status" => 200
            ];
        } else {
            return [
                "response_body" => [
                    'message' => 'Authentication has failed!',  // User credentials are invalid
                    'authentication_server_response' => $auth_server_response
                ],
                "status" => $errorCode
            ];
        }
    }
    catch (\Exception $e) {
        return [
            "response_body" => [
                'message' => 'Authentication has failed!',  // User credentials are invalid
            ],
            "status" => 401
        ];
    }
}

排查与解决步骤

1. 修正请求体编码格式

Laravel Passport的/oauth/token端点默认要求请求体为application/x-www-form-urlencoded格式,而非application/json。原代码通过全局request()添加参数后创建新请求,可能未正确设置请求头。修改代码,直接在新Request实例中传入参数并指定编码:

public function login($email, $password)
{
    try {
        $params = [
            'grant_type' => 'password',
            'client_id' => config('auth.passport_config.client_id'),
            'client_secret' => config('auth.passport_config.client_secret'),
            'username' => $email,
            'password' => $password,
            'scope' => '',
        ];

        $request = Request::create(
            config('auth.passport_config.server_url') . '/oauth/token',
            'POST',
            $params,
            [], // Cookies
            [], // Files
            ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']
        );

        $response = Route::dispatch($request);
        // 后续逻辑保持不变
    } catch (\Exception $e) {
        // 异常处理保持不变
    }
}

2. 验证Docker环境下的Passport客户端

本地环境的Passport客户端数据与Docker数据库可能不一致,导致client_id/client_secret无效:

  • 进入Laravel API容器:docker exec -it <api容器名称> bash
  • 重新创建密码授权客户端:php artisan passport:client --password
  • 将生成的client_id和client_secret更新到容器的环境变量或配置文件中(避免硬编码)

3. 检查Docker网络内的请求地址

确保config('auth.passport_config.server_url')使用Docker网络内的容器名称(如http://laravel-api:8000),而非本地的localhost或127.0.0.1,否则请求无法正确路由到API容器。

4. 开启日志排查请求参数

开启Laravel debug日志,确认请求到达Passport时的实际参数:

  • 在.env中设置LOG_LEVEL=debug
  • 查看容器日志:docker logs <api容器名称>,检查请求体是否包含所有必填参数

5. 避免全局request()参数污染

原代码修改全局request()的参数后创建新请求,在Docker并发场景下可能出现参数污染,直接在新Request实例中传入参数更可靠(如步骤1所示)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:23:20