我一直在为Symfony4这个问题而奋斗,现在终于找到了解决方案。
问题是,在我的情况下,角色取决于用户所属的“公司”。他可能是一家公司的首席执行官,但在另一家公司中是操作员,而菜单、权限等都取决于公司。当切换公司时,用户不应该重新登录。
最后我做了以下几点:
- 将防火墙设置为无状态。
- 在FormAuthentication类中,我明确地在会话中设置了一个属性,即用户名。
- 我设置了另一个Guard,它基本上使用这个属性,并在每个请求中从数据库加载相应的用户。
class FormAuthenticator extends AbstractFormLoginAuthenticator
{
public function supports(Request $request)
{
return 'app_login' === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'nomusuari' => $request->request->get('nomusuari'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['nomusuari']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $userProvider->loadUserByUsername($credentials['nomusuari']);
if (!$user) {
throw new CustomUserMessageAuthenticationException('Invalid user/password');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
$valid = $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
return $valid;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$request->getSession()->set("user_username",$token->getUsername());
return new RedirectResponse(
$this->urlGenerator->generate("main")
);
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate('app_login');
}
}
SessionAuthenticator(返回JSON,您可能需要进行调整):
class SessionAuthenticator extends AbstractGuardAuthenticator
{
public function supports(Request $request)
{
return $request->getSession()->has("user_username");
}
public function getCredentials(Request $request)
{
return $request->getSession()->get("user_username","");
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
if (null === $credentials) {
return null;
}
return $userProvider->loadUserByUsername($credentials);
}
public function checkCredentials($credentials, UserInterface $user)
{
return true;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
$data = [
'message' => strtr($exception->getMessageKey(), $exception->getMessageData())
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function start(Request $request, AuthenticationException $authException = null)
{
$data = [
'message' => 'Authentication Required'
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
public function supportsRememberMe()
{
return false;
}
}
最后,我的security.yaml文件:
main:
anonymous:
stateless: true
guard:
entry_point: App\Security\FormAuthenticator
authenticators:
- App\Security\SessionAuthenticator
- App\Security\FormAuthenticator
工作正常。我可以看到工具栏中的更改,角色已刷新。
希望对你有所帮助,
Esteve
FOS\UserBundle\Model\User
,我的用户实体继承了它。我只是将EquatableInterface
实现到其中,它就像魔法一样运行了(因为FOS的用户已经完成了序列化)。 - juugaEquatableInterface
时,Symfony将跳过所有其他检查以检查用户是否已更改(请参见https://github.com/symfony/security-core/blob/master/Authentication/Token/AbstractToken.php#L250)。所以我猜您必须在`isEqualTo`函数中自己完成所有这些事情? - vincecorereturn count($this->getRoles()) == count($user->getRoles()) && count(array_diff($this->getRoles(), $user->getRoles())) == 0;
- fracz