请求在身份验证后重定向期间挂起
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请求在身份验证后重定向期间挂起相关的知识,希望对你有一定的参考价值。
我正在使用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 LcobucciJWTParser;
use LcobucciJWTValidationData;
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 JumbojettOpenIDConnectClient;
use JumbojettOpenIDConnectClientException;
use LcobucciJWTBuilder;
use LcobucciJWTSignerHmacSha256;
use LcobucciJWTSignerKey;
/**
* 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());
}
}
非常感谢任何建议/建议!
问题是重定向不安全,因为应用服务器正在运行HTTP(在代理处终止了SSL)。将login()
中的MainController.php
的最后一行更改为
return $this->redirect(Router::url('/', true)); // generate full URL
并将fullBaseUrl
中的config/app.php
设置为'https://mydomain.local'
解决了该问题。
以上是关于请求在身份验证后重定向期间挂起的主要内容,如果未能解决你的问题,请参考以下文章
通过 Google 打开 auth 2.0 身份验证后重定向 url 无效