请求在身份验证后重定向期间挂起

问题描述 投票:0回答:1

我正在使用dockerized开发环境开发React / CakePHP应用。为了进行身份验证,我使用OpenID Connect提供程序来建立用户身份,然后按照this article中的建议将其封装在JWT中。使用CakePHP/Authentication插件,我将请求从“ https://mydomain.local/”重定向到“ https://mydomain.local/login”,该请求处理OIDC逻辑。通过身份验证后,用户将再次重定向回站点根,现在JWT包含在两个cookie中。

我的问题是该请求挂在该最终重定向上。如果在设置cookie后禁用重定向并手动导航回root,则请求运行正常,并且我的应用可以通过JWT正确查看经过身份验证的用户。

对于我的开发环境,我使用Caddy容器作为代理以终止https,并使用php-apache容器托管应用程序本身。服务器的日志均未显示发生了最终请求。

以下是我的代码的相关部分:

docker_compose.yml:

services:
  caddy:
    image: "abiosoft/caddy:latest"
    volumes:
      - ./caddy/certs:/root/certs
      - ./caddy/Caddyfile:/etc/Caddyfile
      - ./caddy/logs:/var/log
    ports:
      - "443:2015"
    depends_on:
      - web
  web:
    build:
      context: .
    links:
      - db
    volumes:
      - "./src:/var/www/html/src:rw"
  db:
    image: mysql:latest

caddy / Caddyfile:

mydomain.local {
    log /var/log/access.log
    # Mkcert - https://github.com/FiloSottile/mkcert
    tls /root/certs/mydomain.local.pem /root/certs/mydomain.local-key.pem

    proxy / http://web:80 {
        transparent
    }

}

src / Application.php:

public function middleware($middlewareQueue)
    {
        $middlewareQueue
            ->add(new ErrorHandlerMiddleware(null, Configure::read('Error')))
            ->add(new AssetMiddleware([
                'cacheTime' => Configure::read('Asset.cacheTime')
            ]))
            ->add(new RoutingMiddleware($this))
            ->prepend(new JwtMiddleware())
            ->add(new AuthenticationMiddleware($this));

        return $middlewareQueue;
    }

    public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
    {
        $service = new AuthenticationService([
            'unauthenticatedRedirect' => Router::url(['controller' => 'Main', 'action' => 'login']),
            'queryParam' => 'redirect',
        ]);

        $service->loadIdentifier('Authentication.JwtSubject', [
            'tokenField' => 'id',
            'dataField' => 'sub',
            'resolver' => 'Authentication.Orm',
        ]);
        $service->loadAuthenticator('Authentication.Jwt', [
            'header' => 'Authorization',
            'queryParam' => 'token',
            'tokenPrefix' => 'Bearer',
            'algorithms' => ['HS256'],
            'returnPayload' => 'false',
            'secretKey' => Security::getSalt(),
        ]);

        return $service;
    }

src / Middleware / JwtMiddleware.php:

use Lcobucci\JWT\Parser;
use Lcobucci\JWT\ValidationData;

class JwtMiddleware
{
    public function __invoke(RequestInterface $request, ResponseInterface $response, $next)
    {
        $jwt[0] = $request->getCookie('sa');
        $jwt[1] = $request->getCookie('sb');

        if (!empty($jwt[0]) && !empty($jwt[1])) {
            $data = new ValidationData();
            $data->setIssuer('mydomain');
            $data->setAudience('mydomain.local');
            $data->setId('mydomain');

            $jwt = implode('.', $jwt);
            $token = (new Parser())->parse((string) $jwt);

            if ($token->validate($data)) {
                $request = $request->withAddedHeader('Authorization', 'Bearer ' . $jwt);
                $response = $response->withCookie((new Cookie('sa'))
                    ->withValue($token->getPayload())
                    ->withExpiry(new \DateTime('+30 minutes'))
                    ->withPath('/')
                    ->withHttpOnly(false)
                );
            }
        }

        return $next($request, $response);
    }
}

src / Controller / MainController.php:

use Jumbojett\OpenIDConnectClient;
use Jumbojett\OpenIDConnectClientException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;

/**
 * Main Controller
 *
 * @property UsersTable $Users
 */
class MainController extends AppController
{
    public function beforeFilter(Event $event)
    {
        $this->Authentication->allowUnauthenticated(['login']);

        return parent::beforeFilter($event);
    }

    /**
     * Index method
     *
     * @return Response|null
     */
    public function index()
    {
        $filePath = WWW_ROOT . '/static.html';
        $file = new File($filePath);

        $index = $file->read();
        $file->close();

        return $this->response->withStringBody($index);
    }

    /**
     * Login method
     *
     * @return Response|null
     * @throws OpenIDConnectClientException
     */
    public function login()
    {
        $oidc = new OpenIDConnectClient(
            env('OIDC_URL'),
            env('OIDC_CLIENT'),
            env('OIDC_SECRET')
        );
        $oidc->addScope('openid');
        $oidc->addScope('profile');
        $oidc->authenticate();

        $this->loadModel('Users');

        $user = $this->Users->find()
            ->where(['auth_id' => $oidc->requestUserInfo('sub')])
            ->firstOrFail();

        $signer = new Sha256();
        $time = time();
        $token = (new Builder())
            ->issuedBy('mydomain')
            ->permittedFor('mydomain.local')
            ->identifiedBy('mydomain')
            ->issuedAt($time)
            ->expiresAt($time + 3600)
            ->withClaim('sub', $user->id)
            ->getToken($signer, new Key(Security::getSalt()));

        $signature = explode('.', $token->__toString())[2];
        $sa = (new Cookie('sa'))
            ->withValue($token->getPayload())
            ->withExpiry(new \DateTime('+30 minutes'))
            ->withPath('/')
            ->withHttpOnly(false);
        $sb = (new Cookie('sb'))
            ->withValue($signature)
            ->withPath('/')
            ->withHttpOnly(true);

        $this->response = $this->response
            ->withCookieCollection(new CookieCollection([$sa, $sb]));

        /**** HANG OCCURS ON THIS LINE ****/
        return $this->redirect($this->Authentication->getLoginRedirect());
    }
}

非常感谢任何建议/建议!

php docker authentication cakephp jwt
1个回答
0
投票

问题是重定向不安全,因为应用服务器正在运行HTTP(在代理处终止了SSL)。将login()中的MainController.php的最后一行更改为

return $this->redirect(Router::url('/', true)); // generate full URL

并将fullBaseUrl中的config/app.php设置为'https://mydomain.local'解决了该问题。

© www.soinside.com 2019 - 2024. All rights reserved.