我正在尝试仅在产品环境中通过Symfony 4项目上的OpenId Connect实现身份验证。 我创建了一个扩展GuardAuthenticator的类,它必须实现几种方法:supports,getCredentials,getUser,checkCredentials,onAuthenticationSuccess等...
我正在使用Jumbojett \ OpenIDConnectClient。
我找不到任何可以帮助我构造该GuardAuthenticator类的教程或文档。
(对我而言)OpenId Connect拥有沉重的协议,但是Jumbojett \ OpenIDConnectClient可以很好地对其进行排序。但是,我想在GuardAuthenticator的正确方法中正确使用它。
目前,我的问题是正确构造GuardAuthenticator的代码。
该项目在Linux Debian,php 7.1和Symfony 4上运行。 我的OpenID提供程序是本地计算机上的Keycloak容器。但是,该项目必须使用与Keycloak稍有不同的公司OpenId Provider。而且我很少能在上面测试我的代码。
我扩展GuardAuthenticator的类CustomAuthenticator正在使用OpenIDConnectClient在方法“ getCredentials”中完成整个过程。
当用户通过OpenId Provider进行身份验证时,我的类进入方法“ onAuthenticationSuccess”,并将ID令牌存储在Session(和数据库用户对象)中。 在“ onAuthenticationSuccess”之后,脚本进入重定向的Controller,然后以编程方式登录用户。
在那之后,我使用(GuardAuthenticator的)“ supports”方法来检查会话中的ID令牌,然后检查了一些作为JWT签名的东西(我不确定在那儿检查什么。我要求从我的OpenID提供程序验证会话ID令牌?)。
我真的不知道是否可以。它似乎在某个时候起作用。 将ID令牌存储在会话中以便检查用户身份验证是否可以?
任何帮助表示赞赏。
<?php
//...
use Doctrine\ORM\EntityManagerInterface;
//..
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Jumbojett\OpenIDConnectClient;
class MyGuardAuthenticator extends AbstractGuardAuthenticator
{
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
$this->openIdConfig = $this->getOpenIdConfig();
$this->openIdConnector = $this->initOpenIdConnect();
}
//...
public function checkCredentials($credentials, UserInterface $user)
{
// What should i do here?
return true;
}
//...
// I check if user has to authenticate against OpenID Provider
public function supports(Request $request)
{
if (isset($_SESSION['id_token'])) {
$idToken = $_SESSION['id_token'];
$existingUser = $this->em->getRepository(User::class)
->findOneBy(['idToken' => $idToken]);
if (null === $existingUser) {
return true;
}
// Signature false?
$isOk = $this->openIdConnector->verifyJWTsignature($idToken);
if (!$isOk) {
return true;
}
$idTokenPayload = $this->decodeJWT($idToken, 1);
// expired?
$now = new \DateTime();
if ($now->getTimeStamp() > (int) $idTokenPayload->exp) {
return true;
}
//Accept authenticated user
return false;
}
return true;
}
// I start the protocol here
public function getCredentials(Request $request)
{
$data = $this->callProvider();
return $data->preferred_username;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$existingUser = $this->em->getRepository(User::class)
->findOneBy(['username' => strtoupper($credentials)]);
if ($existingUser) {
return $existingUser;
}
}
//...
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$existingUser = $this->em->getRepository(User::class)
->findOneBy(['username' => $token->getUsername()]);
if ($existingUser) {
$existingUser->setIdToken($_SESSION['id_token']);
$this->em->flush();
}
return null;
}
public function start(Request $request, AuthenticationException $authException = null)
{
return new RedirectResponse(
'/login/', // might be the site, where users choose their oauth provider
Response::HTTP_TEMPORARY_REDIRECT
);
}
//...
private function callProvider()
{
$this->openIdConnector->setRedirectURL($this->openIdConfig['redirect_uri']);
$this->openIdConnector->providerConfigParam(
array(
'issuer' => self::BASE_URL.'/auth/realms/myrealm',
'authorization_endpoint' =>
self::BASE_URL."/auth/realms/myrealm/protocol/openid-connect/auth?scope=openid",
'token_endpoint' =>
self::BASE_URL."/auth/realms/myrealm/protocol/openid-connect/token",
'userinfo_endpoint' =>
self::BASE_URL."/auth/realms/myrealm/protocol/openid-connect/userinfo",
'end_session_endpoint' =>
self::BASE_URL."/auth/realms/myrealm/protocol/openid-connect/logout",
'registration_endpoint' =>
self::BASE_URL."/auth/realms/myrealm/clients-registrations/openid-connect",
'jwks_uri' =>
self::BASE_URL."/auth/realms/myrealm/protocol/openid-connect/certs",
'token_endpoint_auth_methods_supported' => array('authorization_code'),
)
);
$this->openIdConnector->addScope($this->openIdConfig['scope']);
$this->openIdConnector->setVerifyPeer(false);
$this->openIdConnector->authenticate();
$token = $this->openIdConnector->getIdToken();
if (null !== $token) {
$_SESSION['id_token'] = $token;
}
$data = $this->openIdConnector->requestUserInfo();
return $data;
}