net*_*key 21 security roles symfony symfony-2.1 symfony-security
首先,我没有使用FOSUserBundle,我不能,因为我正在移植一个遗留系统,它有自己的模型层(没有Doctrine/Mongo /无论在这里)和其他非常自定义的行为.
我正在尝试将我的遗留角色系统与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;
}
Run Code Online (Sandbox Code Playgroud)
(refreshUser
看起来很相似)
有没有办法让Symfony在每个请求上刷新用户角色?
net*_*key 21
因此,经过几天努力寻找可行的解决方案并为Symfony2用户邮件列表做出贡献,我终于找到了它.以下内容源自https://groups.google.com/d/topic/symfony2/NDBb4JN3mNc/discussion上的讨论
事实证明,有一个接口Symfony\Component\Security\Core\User\EquatableInterface
不是用于比较对象标识,而是用于比较
测试两个对象在安全性和重新认证上下文中是否相等
在您的用户类中实现该接口(已经实现的接口UserInterface
).实现唯一必需的方法,isEqualTo(UserInterface $user)
以便在当前用户的角色与传递的用户的角色不同时返回false.
注意:User对象在会话中序列化.由于序列化的工作方式,请确保将角色存储在用户对象的字段中,而不是直接在getRoles()
Method中检索它们,否则所有这些都不起作用!
以下是特定方法的示例:
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;
}
Run Code Online (Sandbox Code Playgroud)
另请注意,当角色实际更改并重新加载页面时,探查器工具栏可能会告诉您未对用户进行身份验证.另外,查看分析器,您可能会发现角色实际上没有刷新.
我发现刷新的角色确实有效.只是如果没有命中授权约束(没有@Secure
注释,防火墙中没有必需的角色等),则实际上不会刷新并且用户保持在"未经身份验证"状态.
只要您点击执行任何类型授权检查的页面,用户角色就会刷新,并且探查器工具栏会显示带有绿点的用户,并再次显示"已验证:是".
这对我来说是可接受的行为 - 希望它有用:)
Mar*_*arc 11
在您的security.yml(或替代方案)中:
security:
always_authenticate_before_granting: true
Run Code Online (Sandbox Code Playgroud)
我生命中最轻松的游戏.
在Controller中,将角色添加到用户并保存到数据库后,只需调用:
// Force refresh of user roles
$token = $this->get('security.context')->getToken()->setAuthenticated(false);
Run Code Online (Sandbox Code Playgroud)