我想为部分用户登录后集成辅助身份验证措施:
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$user = $token->getUser();
if ($user->getOrganization()->getMfa() {
//$token->setAuthenticated(false);
$token->setRoles(null);
return new RedirectResponse($this->router->generate('mfa'));
}
return new RedirectResponse($this->router->generate('home'));
}
然后,我想在其他控制器中验证安全代码:
if((int)$session->get('authCode') === (int)$request->get('auth_code')) {
//$token->setAuthenticated(true);
$token->setRoles($user->getRoles());
return new RedirectResponse($this->router->generate('home'));
}
setAutheticated(false)
的问题是方法完成后,我无法访问$user
对象。
我正在考虑删除授予用户的角色;但我不知道如何从现有令牌中删除角色。
答案 0 :(得分:1)
您无法设置令牌的role属性。如您所见,TokenInterface
不包含角色的设置器。
您不能setAuthenticated(false)
,因为那样您将清除第一个身份验证因素,并将bac设置为零。
但是我相信您正在以错误的方式解决问题。
保留令牌,并使用onAuthenticationSuccess
的侦听器检查User::organization::getMfa()
以确定是否需要:
(就我个人而言,我将MFA的要求设置为另一个角色,因此可以将其存储在令牌中,而您无需为此检查其他事项)。
然后,为每个请求创建一个event subscriber。
在该侦听器上,您需要注入use Symfony\Component\Security\Core\Security
来访问用户,并查看是否User::organization::getMfa() === true
;以及检查身份验证是否完成的任何方式(例如,是否存储在会话中,或直接检查用户实体等)。
如果您没有令牌,则return
,这是未经身份验证的视图,而不是侦听器问题。
如果用户不需要MFA,则只需return
;这里没事。
如果用户需要MFA,但不在认证过程中,则您return
。这意味着用户已经通过了完整的身份验证,可以继续进行操作。
如果用户需要MFA并且处于身份验证过程的中间,则您将显示完成该身份的任何方式。通常是表格。
如果用户需要MFA并且处于身份验证过程中,并且他们向您发送了检查此身份验证的方式(例如,带有相应字段的POST请求),则您验证身份验证是否正确。
验证好吗?您清除“身份验证正在进行中”位,然后返回。进一步的请求将不会被拦截。
验证不正确吗?您要么让他们再次检查,然后重新发送验证码,然后将用户完全注销,以便他们再次开始...究竟这取决于您的要求。
完整的代码实现将取决于您,因为它不可能涵盖所有可能的情况。
但是,您的订阅者可能会是这样的(请注意,还有两个未实现的方法)。
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
class MfaSubscriber implements EventSubscriberInterface
{
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
public function onRequest(RequestEvent $event)
{
if ($event->getRequestType() === HttpKernelInterface::SUB_REQUEST) {
return;
}
$request = $event->getRequest();
if ( null == $token = $this->security->getToken()) {
return;
}
if ( ! in_array('ROLE_NEEDS_MFA', $token->getRoleNames(), true)) {
return;
}
if ( ! $request->hasPreviousSession() || ! $request->getSession()->get('AUTHENTICATION_IN_PROCESS')) {
return;
}
if (
$request->getMethod() === Request::METHOD_POST
&& $request->get('verification_code')
&& $this->verifyCode($request->get('verification_code')) // verify code needs to be implemented
) {
$request->getSession()->set('AUTHENTICATION_IN_PROCESS', null);
return;
}
$event->setResponse($this->displayMfaVerificationMethod($request, $token));
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => 'onRequest',
];
}
}