首先,我没有使用FOSUserBundle,我不能,因为我移植有其自身的模型层(无主义/蒙戈/任何在这里)等非常自定义行为的遗留系统。
我想我的遗产的角色系统的Symfony的连接,所以我可以在控制器和视图使用本地symfony的安全性。
我的第一次尝试加载并返回该用户的所有角色中的getRoles()
从方法Symfony\Component\Security\Core\User\UserInterface
。 起初,它看起来像工作。 再从更深层面看后,我注意到,这些角色只有刷新时,用户登录这意味着,如果授予或吊销用户角色,他将不得不注销并重新登录以使更改生效。 不过,如果我撤销安全角色从一个用户,我想,要立即应用,这样的行为是不能接受我。
我想要的Symfony做的是重新加载每个请求的用户的角色,以确保他们跟上时代的。 我实现了一个自定义的用户提供其refreshUser(UserInterface $user)
方法被调用每个请求,但不知何故角色没有被刷新。
代码加载/刷新我的UserProvider用户看起来是这样的:
public function loadUserByUsername($username) {
$user = UserModel::loadByUsername($username); // Loads a fresh user object including roles!
if (!$user) {
throw new UsernameNotFoundException("User not found");
}
return $user;
}
( refreshUser
比较相似)
有没有一种方法,使每个请求的Symfony刷新用户角色吗?
所以经过几天的努力找到一个可行的解决方案,并促进了Symfony2的用户邮件列表,我终于找到了。 下面已经从讨论中得出的https://groups.google.com/d/topic/symfony2/NDBb4JN3mNc/discussion
事实证明,有一个接口Symfony\Component\Security\Core\User\EquatableInterface
是不适合的对象身份,但恰恰比较
如果测试两个对象是在安全和重新认证上下文等
实现你的用户类接口(一个已经实现UserInterface
)。 实施所需的唯一方法isEqualTo(UserInterface $user)
,这样,如果当前用户的角色不同于传递用户的不同返回false。
注:用户对象是在会话序列化。 因为这样系列化作品的,请务必将角色存储在用户对象的字段,并且不直接在检索它们getRoles()
方法,否则,所有的这是行不通的!
下面是具体的方法如何可能看起来像一个例子:
protected $roles = null;
public function getRoles() {
if ($this->roles == null) {
$this->roles = ...; // Retrieve the fresh list of roles
// from wherever they are stored here
}
return $this->roles;
}
public function isEqualTo(UserInterface $user) {
if ($user instanceof YourUserClass) {
// Check that the roles are the same, in any order
$isEqual = count($this->getRoles()) == count($user->getRoles());
if ($isEqual) {
foreach($this->getRoles() as $role) {
$isEqual = $isEqual && in_array($role, $user->getRoles());
}
}
return $isEqual;
}
return false;
}
另外,还要注意的是,当角色的真正改变和重新载入页面,分析器工具栏可能会告诉你,你的用户没有通过验证。 此外,寻找到的探查,你可能会发现角色实际上并没有得到刷新。
我发现这个角色其实清爽不工作。 只是,如果没有授权约束被击中(无@Secure
注释,无需在防火墙等角色),刷新实际上没有完成,用户保存在“未”状态。
只要你打在执行任何类型的授权检查的页面,用户角色被刷新,并剖析工具栏显示有绿点和“验证:是”用户再次。
这对我来说是可以接受的行为 - 希望这是有益的:)
在您的security.yml(或替代):
security:
always_authenticate_before_granting: true
我的生活的最简单的游戏。
从控制器,添加角色给用户,并保存到数据库后,只需拨打:
// Force refresh of user roles
$token = $this->get('security.context')->getToken()->setAuthenticated(false);
看看这里 ,设置always_authenticate_before_granting
到true
的security.yml
。
我实现通过实现我自己的EntityUserProvider和压倒一切的loadByUsername($用户名)方法,此行为:
/**
* Load an user from its username
* @param string $username
* @return UserInterface
*/
public function loadUserByUsername($username)
{
$user = $this->repository->findOneByEmailJoinedToCustomerAccount($username);
if (null === $user)
{
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
}
//Custom function to definassigned roles to an user
$roles = $this->loadRolesForUser($user);
//Set roles to the user entity
$user->setRoles($roles);
return $user;
}
诀窍是调用setRoles
你打电话,每次loadByUsername
...希望它可以帮助
解决办法是挂在学说postUpdate事件的订户。 如果有更新的实体是用户,因为登录同一用户,那我用的AuthenticationManager服务认证。 你必须注入服务容器(或相关服务)到用户的,当然。 我更愿意注入整个容器,以防止循环引用的问题。
public function postUpdate(LifecycleEventArgs $ev) {
$entity = $ev->getEntity();
if ($entity instanceof User) {
$sc = $this->container->get('security.context');
$user = $sc->getToken()->getUser();
if ($user === $entity) {
$token = $this->container->get('security.authentication.manager')->authenticate($sc->getToken());
if ($token instanceof TokenInterface) {
$sc->setToken($token);
}
}
}
}
对不起,我不能在评论,所以我重播质疑答复。 如果有人在symfony的安全性的新尝试让角色刷新工作的自定义密码验证,然后内部功能authenticateToken:
if(count($token->getRoles()) > 0 ){
if ($token->getUser() == $user ){
$passwordValid=true;
}
}
不要检查从DB / LDAP或任何密码。 如果用户系统进来,然后在$令牌只是用户名,也没有作用。
现在的Symfony 4.1是在这里一段时间,
我通过解决问题手动认证用户 。