Symfony2 FOS 用户密码校验回调约束
Symfony2 FOS User password check callback constraint
我在自己创建的多站点平台上使用 FOS User Bundle。
我需要根据用户角色设置密码检查的自定义约束(对管理员用户进行更强的正则表达式检查)。
我如何以及在哪里可以挂钩以安全地执行此操作? Assert/Constraint 似乎不能用于用户实体,例如 this answer 不允许对角色进行不同的检查。
感谢您的回答,
尼古拉斯
您可以创建自定义验证约束并将其附加到 class 而不是 属性。
Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex
namespace Acme\UserBundle\Validator\Constraints;
/**
* @Annotation
* @Target({"CLASS", "ANNOTATION"})
*/
class PasswordForRoleRegex extends Constraint
{
/**
* {@inheritdoc}
*/
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
}
Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex验证者
namespace Acme\UserBundle\Validator\Constraints;
class PasswordForRoleRegexValidator extends ConstraintValidator
{
const REGEX_SUPER_ADMIN = '/..../';
// or an actual message if you don't use translations
const MESSAGE_SUPER_ADMIN = 'acme.user.password.regex.super_admin';
const REGEX_ADMIN = '/..../';
const MESSAGE_ADMIN = 'acme.user.password.regex.admin';
/// and so on
const REGEX_NORMAL_USER = '/..../';
const MESSAGE_NORMAL_USER = 'acme.user.password.regex.normal_user';
public function validate($user, Constraint $constraint)
{
if (!$constraint instanceof PasswordForRoleRegex) {
throw new UnexpectedTypeException($constraint, PasswordForRoleRegex::class);
}
if (!$user instanceof UserInterface) {
throw new UnexpectedTypeException($user, UserInterface::class);
}
if (null === $password = $user->getPlainPassword()) {
return;
}
if (preg_match($this->getPasswordRegexForUserRole($user), $password) {
return;
}
$this->context->buildViolation($this->getErrorMessageForUserRole($user))
->atPath('plainPassword')
->addViolation();
}
/**
* @param UserInterface $user
* @return string
*/
private function getPasswordRegexForUserRole(UserInterface $user)
{
if ($user->hasRole('ROLE_SUPER_ADMIN')) {
return self::REGEX_SUPER_ADMIN;
}
if ($user->hasRole('ROLE_ADMIN')) {
return self::REGEX_ADMIN;
}
// and so on
return self::REGEX_NORMAL_USER;
}
/**
* @param UserInterface $user
* @return string
*/
private function getErrorMessageForUserRole(UserInterface $user)
{
if ($user->hasRole('ROLE_SUPER_ADMIN')) {
return self::MESSAGE_SUPER_ADMIN;
}
if ($user->hasRole('ROLE_ADMIN')) {
return self::MESSAGE_ADMIN;
}
// and so on
return self::MESSAGE_NORMAL_USER;
}
}
然后您可以在验证中使用它,例如...
Acme\UserBundle\Model\User
namespace Acme\UserBundle\Model;
use Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex;
use FOS\UserBundle\Model\User as BaseUser;
/**
* @PasswordForRoleRegex(groups={"Registration", "ChangePassword", ....})
*/
class User extends BaseUser
{
//...
}
或..
@AcmeUserBundle/Resources/config/validation.yml
Acme\UserBundle\Model\User:
properties:
Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex:
groups: ["Registration", "ChangePassword", ....]
或XML我懒得去做。
我很确定这会起作用,但它没有经过测试,所以它可能不是 100%。
我在自己创建的多站点平台上使用 FOS User Bundle。 我需要根据用户角色设置密码检查的自定义约束(对管理员用户进行更强的正则表达式检查)。
我如何以及在哪里可以挂钩以安全地执行此操作? Assert/Constraint 似乎不能用于用户实体,例如 this answer 不允许对角色进行不同的检查。
感谢您的回答,
尼古拉斯
您可以创建自定义验证约束并将其附加到 class 而不是 属性。
Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex
namespace Acme\UserBundle\Validator\Constraints;
/**
* @Annotation
* @Target({"CLASS", "ANNOTATION"})
*/
class PasswordForRoleRegex extends Constraint
{
/**
* {@inheritdoc}
*/
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
}
Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex验证者
namespace Acme\UserBundle\Validator\Constraints;
class PasswordForRoleRegexValidator extends ConstraintValidator
{
const REGEX_SUPER_ADMIN = '/..../';
// or an actual message if you don't use translations
const MESSAGE_SUPER_ADMIN = 'acme.user.password.regex.super_admin';
const REGEX_ADMIN = '/..../';
const MESSAGE_ADMIN = 'acme.user.password.regex.admin';
/// and so on
const REGEX_NORMAL_USER = '/..../';
const MESSAGE_NORMAL_USER = 'acme.user.password.regex.normal_user';
public function validate($user, Constraint $constraint)
{
if (!$constraint instanceof PasswordForRoleRegex) {
throw new UnexpectedTypeException($constraint, PasswordForRoleRegex::class);
}
if (!$user instanceof UserInterface) {
throw new UnexpectedTypeException($user, UserInterface::class);
}
if (null === $password = $user->getPlainPassword()) {
return;
}
if (preg_match($this->getPasswordRegexForUserRole($user), $password) {
return;
}
$this->context->buildViolation($this->getErrorMessageForUserRole($user))
->atPath('plainPassword')
->addViolation();
}
/**
* @param UserInterface $user
* @return string
*/
private function getPasswordRegexForUserRole(UserInterface $user)
{
if ($user->hasRole('ROLE_SUPER_ADMIN')) {
return self::REGEX_SUPER_ADMIN;
}
if ($user->hasRole('ROLE_ADMIN')) {
return self::REGEX_ADMIN;
}
// and so on
return self::REGEX_NORMAL_USER;
}
/**
* @param UserInterface $user
* @return string
*/
private function getErrorMessageForUserRole(UserInterface $user)
{
if ($user->hasRole('ROLE_SUPER_ADMIN')) {
return self::MESSAGE_SUPER_ADMIN;
}
if ($user->hasRole('ROLE_ADMIN')) {
return self::MESSAGE_ADMIN;
}
// and so on
return self::MESSAGE_NORMAL_USER;
}
}
然后您可以在验证中使用它,例如...
Acme\UserBundle\Model\User
namespace Acme\UserBundle\Model;
use Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex;
use FOS\UserBundle\Model\User as BaseUser;
/**
* @PasswordForRoleRegex(groups={"Registration", "ChangePassword", ....})
*/
class User extends BaseUser
{
//...
}
或..
@AcmeUserBundle/Resources/config/validation.yml
Acme\UserBundle\Model\User:
properties:
Acme\UserBundle\Validator\Constraints\PasswordForRoleRegex:
groups: ["Registration", "ChangePassword", ....]
或XML我懒得去做。
我很确定这会起作用,但它没有经过测试,所以它可能不是 100%。