Laravel 中间件中的依赖注入

Laravel Dependency Injection in Middleware

我正在使用 Laravel-5.0 的默认 Authentication 中间件,但我将句柄函数的签名更改为:

public function handle($request, Closure $next, AuthClientInterface $authClient)

我还在以下服务提供商中注册了 AuthClientInterface

public function register()
{
    $this->app->bind('App\Services\Contracts\AuthClientInterface', function()
    {
        return new AuthClient(
            env('AUTH_SERVER_URL'),
            env('AUTH_SESSION_URL'),
            env('AUTH_CLIENT_ID')
        );
    });
}

然而,尽管如此,我还是看到了以下错误:

Argument 3 passed to HelioQuote\Http\Middleware\Authenticate::handle() 
must be an instance of 
HelioQuote\Services\Contracts\HelioAuthClientInterface, none given, 
called in C:\MyApp\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php on line 125 and defined...

谁能看出我做错了什么?

编辑:我确实通过将 HelioAuthClientInterface 传递给中间件的构造函数来让它工作。但是我认为除了构造函数之外,IoC 容器还会将依赖项注入到方法中。

您不能直接在 Request 中的 handle 方法中进行依赖注入,而是在构造函数中进行。

中间件被call_user_func调用,所以这里的任何注入都不起作用。

<?php

namespace App\Http\Middleware;

use Closure;
use App\Foo\Bar\AuthClientInterface; # Change this package name

class FooMiddleware
{
  protected $authClient;

  public function __construct(AuthClientInterface $authClient)
  {
    $this->authClient = $authClient;
  }

  public function handle(Request $request, Closure $next)
  {
    // do what you want here through $this->authClient
  }
}

Laravel的IoC默认只处理所有对象的构造方法注入。 IoC 只会将依赖项注入路由器处理的 functions/methods 中。可以是用于处理路由的闭包,或者更常见的是,用于处理路由的控制器方法。

默认情况下,IoC 不会为任何其他对象执行方法 依赖注入。您可以通过 IoC 自己调用方法并让它解决依赖关系,但框架只为路由处理程序自己做这件事。您可以查看此 question/answer 以获取有关在控制器外部使用方法依赖项注入的更多信息:can I use method dependency injection outside of a controller?.

如果您想继续使用依赖注入,通过构造函数注入依赖项来处理此问题是正确的方法。

您不能在此处更改方法签名。你可以简单地使用这样的东西:

public function handle($request, Closure $next) {

    // Get the bound object to this interface from Service Provider
    $authClient = app('App\Services\Contracts\AuthClientInterface');

    // Now you can use the $authClient
}

此外,您可以使用 __construct 方法来实现,请检查 - Francis.TM.

给出的答案

已接受的答案自 Laravel 5.3.4 起不再有效。 See complain on GitHub and upgrade guide 提供替代方案。

例如,我为解决当前问题而实施的片段:

<?php

namespace App\Http\Middleware;

use Closure;
use App\Models\Website;
use \Illuminate\Http\Request;

class CheckPropertyOfWebsite
{

    protected $website_owner_id;

    public function __construct(Request $request)
    {
        $this->website_owner_id = Website::findOrFail($request->website)->first()->user_id;
    }

    public function handle($request, Closure $next)
    {
        if ($request->user()->id !== $this->website_owner_id) {
            return response(null, 500);
        }
        return $next($request);
    }
}