Не удается переопределить заголовки CORS в Slim Framework

Я использую Slim v3 с промежуточным ПО CORS по адресу https://github.com/tuupola/cors-middleware для обработки заголовков CORS. Все работает, однако теперь мне нужно изменить заголовок Access-Control-Allow-Origin в зависимости от того, под каким именем пользователь входит в систему. У меня есть еще одно промежуточное ПО, которое выполняется после промежуточного ПО CORS для проверки пользователя, и я надеялся, что из этого промежуточного ПО я смогу просто добавить $response = $response->withHeader('Access-Control-Allow-Origin', $userdomain) и он сохранит остальные заголовки CORS, установленные предыдущим промежуточным программным обеспечением, но переопределит этот. Однако, похоже, этого не происходит. Независимо от того, где выполняется это ПО промежуточного слоя, заголовки CORS всегда определяются ПО промежуточного слоя 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);
}

person Matthew Coates    schedule 03.12.2018    source источник


Ответы (2)


Попробуй это:

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
person Ivan Dudarev    schedule 04.12.2018
comment
Извините, что я так долго не отвечал, но мне пришлось обновить wamp и php, чтобы это заработало. К сожалению, похоже, это не работает: до $res = $cors-›process($req, $handler); $res принимает форму объекта Slim\Http\Response, тогда как после этого он принимает форму объекта Zend\Diactoros\Response, который, похоже, не содержит URL-адрес исходного домена. - person Matthew Coates; 10.12.2018
comment
Еще немного исследований показывает, что исходная версия через Tuupola\Middleware\Cors, как и в исходном посте, находится по адресу [tip:protected][static][callable][callable:Slim\DeferredCallable:private][options:Tuupola\Middleware\ Cors:private] в объекте Apps. Версия в этом сообщении помещает его в [tip:protected][static][next][static][callable][callable:Slim\DeferredCallable:private][options:Tuupola\Middleware\Cors:private][origin] — с дополнительный следующий => статический слой - это может быть проблемой - person Matthew Coates; 11.12.2018
comment
Разобрался в чем дело, код авторизации (github.com/thephpleague/oauth2-server на основе Я считаю) конфликтовали - я переместил их в отдельные классы, и это решило это. Спасибо! - person Matthew Coates; 18.12.2018

В промежуточном программном обеспечении вам нужно добавить заголовок ПОСЛЕ обработчика

<?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);
    }
}
person Ivan Dudarev    schedule 03.12.2018
comment
Кажется, это помогает, по крайней мере, теперь я могу обновить Access-Control-Allow-Origin. Еще одна охота за ошибками, но другого рода. Спасибо! - person Matthew Coates; 03.12.2018
comment
К сожалению, я, возможно, был преждевременным с моими предположениями здесь: выходные данные заголовка для Access-Control-Allow-Origin содержат пользовательский домен, но выходные данные Cors, похоже, содержат исходную команду происхождения (''), что означает, что когда тестирование как запрос из домена, отличного от назначенного пользователю, его разрешают пройти, а не блокируют. то есть: исходная переменная объекта options:Tuupola\Middleware\Cors:private остается '' вместо того, чтобы становиться 'blahblahblah' - person Matthew Coates; 04.12.2018
comment
Смотрите мой следующий ответ - person Ivan Dudarev; 07.12.2018