无法在 Slim Framework 中覆盖 CORS headers

Cannot override CORS headers in Slim Framework

我在 https://github.com/tuupola/cors-middleware 使用带有 CORS 中间件的 Slim v3 来处理 CORS header。一切正常,但我现在需要能够根据用户登录身份修改 Access-Control-Allow-Origin header。我有另一个在 CORS 中间件之后执行的中间件来进行用户验证,我希望从这个中间件中我可以添加 $response = $response->withHeader('Access-Control-Allow-Origin', $userdomain) 它会保持由前一个中间件设置的其余 CORS headers,但覆盖那个。然而,这似乎并没有发生。无论此中间件在何处执行,CORS header 始终由 CORS 中间件定义。

当前设置如下所示:

$app->add(new \Internal\OAuth\Middleware($this->getDBs()));

$app->add(new \Tuupola\Middleware\Cors([
    "origin" => ['*'],
    "methods" => ['GET', 'POST', 'PUT', 'OPTIONS', 'DELETE'],
    "headers.allow" => ['', 'Authorization', 'Content-Type', 'Content-Length', 'Origin', 'Accept'],
    "credentials" => true,
    "cache" => 100
]));

\Internal\OAuth\Middleware __invoke 看起来像这样:

public function __invoke($req, $res, $next) {
    //do authentication stuff
    $userdomain = 'http://blahblahblah';
    $res = $res->withHeader('Access-Control-Allow-Origin', $userdomain);
    return $next($req, $res);
}

在中间件中,您需要在处理程序

之后添加一个header
<?php

namespase \Internal\OAuth;

class Middleware
{
    public function __invoke($req, $res, $next) {
        //do authentication stuff
        $userdomain = 'http://blahblahblah';
        $res = $next($req, $res);
        return $res->withHeader('Access-Control-Allow-Origin', $userdomain);
    }
}

试一试:

index.php:

<?php

$app = new \Slim\App();

$app->add(new \Internal\OAuth\Middleware());

$app->get('/', function(\Psr\Http\Message\ServerRequestInterface $req, \Psr\Http\Message\ResponseInterface $res, $args) {
    $res->getBody()->write(json_encode(['url' => $req->getUri()->__toString(), 'args'=>$args]));
    return $res->withHeader('content-type', 'application/json');
});

$app->run();

src/Internal/OAuth/Middleware.php

<?php

namespace Internal\OAuth;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class Middleware
{

    /**
     * @param ServerRequestInterface $req
     * @param ResponseInterface $res
     * @param callable $next
     * @return ResponseInterface
     */
    public function __invoke($req, $res, $next) {
        //do authentication stuff
        $options = [
            "origin" => ['http://blahblahblah'],
            "methods" => ['GET', 'POST', 'PUT', 'OPTIONS', 'DELETE'],
            "headers.allow" => ['', 'Authorization', 'Content-Type', 'Content-Length', 'Origin', 'Accept'],
            "credentials" => true,
            "cache" => 100
        ];
        $cors = new \Tuupola\Middleware\CorsMiddleware($options);
        $handler = new Handler($res, $next);
        $res = $cors->process($req, $handler);
        return $res;
    }
}

src/Internal/OAuth/Handler.php

<?php

namespace Internal\OAuth;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class Handler implements RequestHandlerInterface
{

    protected $callable;

    protected $response;

    public function __construct(ResponseInterface $response, callable $callable)
    {
        $this->callable = $callable;
        $this->response = $response;
    }

    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $handler = $this->callable;
        return $handler($request, $this->response);
    }
}

测试:

1.

curl "http://localhost:8088" --request OPTIONS --include --header "Origin: http://disallowed-host" --header "Access-Control-Request-Method: PUT"

HTTP/1.1 401 Unauthorized
Host: localhost:8088
Date: Tue, 04 Dec 2018 13:19:14 +0700
Connection: close
Content-Length: 0

2.

curl "http://localhost:8088" --request OPTIONS --include --header "Origin: http://blahblahblah" --header "Access-Control-Request-Method: PUT"

HTTP/1.1 200 OK
Host: localhost:8088
Date: Tue, 04 Dec 2018 13:19:04 +0700
Connection: close
Access-Control-Allow-Origin: http://blahblahblah
Access-Control-Allow-Credentials: true
Vary: Origin
Access-Control-Max-Age: 100
Access-Control-Allow-Methods: GET, POST, PUT, OPTIONS, DELETE
Content-Length: 0