【问题标题】:Having trouble rebinding $request->setUserResolver重新绑定 $request->setUserResolver 时遇到问题
【发布时间】:2018-04-06 17:56:05
【问题描述】:

我正在尝试重新绑定$request->user() 返回的内容,并且在浏览了内置身份验证代码后,我发现使用app->rebindingrequest->setUserResolver 的服务是如何完成的?我自己尝试过,没有运气。我创建了一个服务(好吧,选择了 AuthServiceProvider,并将注册表更改为:

public function register()
{
    $this->app->rebinding('request', function ($app, $request) {
        $request->setUserResolver(function () use ($app) {
            $token = $this->request->bearerToken();
            dd($token);
            // error_log($token);
            return array('user' => 1);
        });
    });
}

忽略 dd,这是要测试的,我怎么能找到我哪里出错了?我什至找到了一个 SO 答案,似乎表明这是要走的路,但没有任何东西被转储,没有任何东西被记录(当错误日志没有被注释掉时)并且在我的控制器中转储 $request->user() 只会返回 null。

我知道我可以使用内置的 auth/guard 设置,但我想既然我没有使用 auth/guard 设置的大部分功能,为什么不尝试自己学习和设置呢?当然,到目前为止,我一无所获。我打算回退到使用内置的东西,但我想学习和改进。

当我意识到它可能会有所作为时,我正在运行 Lumen 5.4。

【问题讨论】:

  • 您是否将您的新服务提供商添加到config/app.php in 'providers'
  • 我实际上只是删除了现有AuthServiceProvider 的内容并将其写入register()。没想到这会是个问题?
  • 哦,我以为您将 AuthserviceProvider 复制到了新的提供程序中...不是问题。还要检查How to bind user object to request in a middleware。可以为您指明正确的方向
  • 谢谢。我之前遇到过,我想我应该自己测试一下。如前所述,希望找出我在学习方面做错了什么。
  • 你能提供最小代码 git repo 来调试问题吗?

标签: php laravel laravel-5 lumen


【解决方案1】:

rebinding 方法将添加一个额外的reboundCallbacks,该回调将在抽象反弹后立即触发。只要您的摘要不反弹,reboundCallbacks 就不会被调用。因此,您可以像这样简单地反弹您的摘要:

$this->app->rebinding('request', function ($app, $request) {
    $request->setUserResolver(function () use ($app) {
        $token = $this->request->bearerToken();

        dd($token);

        // do the rest
    });
});

// REBOUND HERE
$this->app->instance('request', $this->app->make('request'));

// TEST
// $this->app->make('request')->user(); // output is $token

尝试取消注释上面的反弹行,你的dd根本不会被调用。

额外

您可以使用refresh 方法(注册reboundCallbacks)结合extend 方法(反弹)以获得更简洁的代码:

public function register()
{
    parent::register();

    $this->app->refresh('request', $this, 'overrideUserResolver');

    // REBOUND HERE, JUST ANOTHER WAY TO REBOUND
    $this->app->extend('request', function ($request) { return $request; });

    // TEST
    $this->app->make('request')->user();
}

public function overrideUserResolver($request)
{
    $request->setUserResolver(function ($guard = null) use ($request) {
        $token = $request->bearerToken();

        dd($token);

        // do the rest
    });
}

【讨论】:

    【解决方案2】:

    不需要更改register() 函数。 只需取消注释bootstrap/app.php 文件中的以下行:

    $app->withEloquent();
    $app->register(App\Providers\AppServiceProvider::class);
    $app->register(App\Providers\AuthServiceProvider::class);
    $app->routeMiddleware([
        'auth' => App\Http\Middleware\Authenticate::class,
    ]);
    

    app/Providers/AuthServiceProvider.php->boot() 中,它有默认方法来检索经过身份验证的用户。

    $this->app['auth']->viaRequest('api', function ($request) {
        if ($request->input('api_token')) {
            return User::where('api_token', $request->input('api_token'))->first();
        }
    });
    

    您可以在请求标头或查询字符串中使用 API 令牌,在请求中使用不记名令牌,或使用您的应用程序需要的任何其他方法。

    之后,您可以像这样检索经过身份验证的用户:

    use Illuminate\Http\Request;
    
    $app->get('/post/{id}', ['middleware' => 'auth', function (Request $request, $id) {
        $user = Auth::user();
    
        $user = $request->user();
    
        //
    }]);
    

    【讨论】:

    • 谢谢,但正如我在回答中提到的,我已经知道我可以通过内置的 Auth/Guard 系统做到这一点;我已经通过文档并已经以这种方式进行了设置。我试图更深入地了解 Laravel/Lumen,因此我试图推断 Auth 系统是如何做到的,这似乎是我上面的做法,除了我的方法不起作用。
    【解决方案3】:

    在 Lumen 中,您的 App\Providers\AuthServiceProvider 类默认带有

    public function boot()
    {
        // Here you may define how you wish users to be authenticated for your Lumen
        // application. The callback which receives the incoming request instance
        // should return either a User instance or null. You're free to obtain
        // the User instance via an API token or any other method necessary.
        $this->app['auth']->viaRequest('api', function ($request) {
            if ($request->input('api_token')) {
                return User::where('api_token', $request->input('api_token'))->first();
            }
        });
    }
    

    这是定义用户解析逻辑的地方。您在 register 方法中注册的重新绑定已被此方法取代。

    只需取消注释bootstrap/app.php 中的$app->register(App\Providers\AuthServiceProvider::class); 行即可注册您的提供商;不要修改vendor 文件夹中的代码(如果我理解正确的话,您就是这样做的)。


    更新

    我现在明白你的意思了,虽然我不确定 auth/guard 方法的“负载”是否真的太多。 但是,为了创建最小的实现,我认为解决方案将覆盖 Application 类的 prepareRequest 方法。

    bootstrap/app.php 中替换

    $app = new Laravel\Lumen\Application(
        realpath(__DIR__.'/../')
    );
    

    $app = new class (realpath(__DIR__.'/../')) extends Laravel\Lumen\Application {
        protected function prepareRequest(\Symfony\Component\HttpFoundation\Request $request)
        {
            if (! $request instanceof Illuminate\Http\Request) {
                $request = Illuminate\Http\Request::createFromBase($request);
            }
    
            $request->setUserResolver(function () use ($request) {
                return $request->bearerToken();
            })->setRouteResolver(function () {
                return $this->currentRoute;
            });
    
            return $request;
        }
    };
    

    通过这种方式,您可以获得简单的解析逻辑来获取不记名令牌(然后不包括 AuthServiceProvider)。

    (这需要 PHP 7 匿名类;或者只是扩展为常规类)。

    【讨论】:

    • 好吧,echos、dds、error_logs 在函数内部甚至都不会触发,所以即使有请求对象也没有。它从未真正进入函数内部。正如我所提到的,我从内置的AuthService 架构中复制了它。如果我可以进入函数,即使请求对象不存在,我也可以提取我需要的标头值。
    • 感谢您的反馈,但正如我在问题末尾提到的,我知道我可以使用内置的 auth/guard 方法,但我希望了解有关 Laravel/Lumen 的更多信息正在幕后工作。我通过供应商追踪viaRequest,发现它正在重新绑定setUserResolver,所以想自己尝试一下。我只是在很大程度上改变了供应商的东西来调试它是如何工作的。内置的 auth/guard 远远超出了我的需要,所以我想学习,这样我可以帮助减少整体负载。我正在从供应商那里复制代码来创建我自己的 AuthServiceProvider。
    • 非常感谢您提供的扩展答案!我一定会深入研究的。你说得对,在这种情况下,“减少负载”可能并不意味着什么。我对学习更感兴趣。我仍然想弄清楚为什么内置的 AuthService 功能与重新绑定一起工作,而我的却没有,但这是一个很好的解释。我会尽快测试。
    猜你喜欢
    • 2012-09-02
    • 2017-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多