问题描述
我正在尝试使用表单中的特定验证器.
Im trying to use a specific validator in a form.
该表格供用户重新定义其密码,他还必须输入其当前密码.为此,我使用了来自symfony的内置验证器
That form is for an user to redefine his password, he must also enter his current password.For that I use a built in validator from symfony
以我的形式:
use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
,表单类型如下:
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('currentpassword', 'password', array('label'=>'Current password',
'mapped' => false,
'constraints' => new UserPassword(array('message' => 'you wot m8?')),
'required' => true
))
->add('password', 'repeated', array(
'first_name' => 'new',
'second_name' => 'confirm',
'type' => 'password',
'required' => true
))
;
}
我知道我可以在控制器中获取数据表格,获取当前密码值,调用security.encoder_factory等,但是该验证程序很方便.
I know in my controller I could just get the data form, get the currentpassword value, call the security.encoder_factory, etc but that validator looked handy.
我的问题是,表单总是返回错误(在这里:"you wot m8?"),就像我输入了错误的当前密码一样.
my problem is that the form always return an error (here: 'you wot m8?') just like I had entered the wrong current password.
知道我在做什么错吗?
推荐答案
我知道这个答案要晚几年了,但是由于我遇到同样的问题,我想提出自己的解决方案:
I know this answer is coming a few years late, but as I was stumbleing ybout the same Problem I want to present my solution:
问题在于,在我的情况下,我用于FormMapping的$user
实体与来自security.context
的User
之间存在联系.
The problem is that there was a connection in my case between the $user
Entity I used for FormMapping and the User
that comes form the security.context
.
请参阅以下内容:(密码更改-控制器)
See following: (PasswordChange - Controller)
$username = $this->getUser()->getUsername();
$user = $this->getDoctrine()->getRepository("BlueChordCmsBaseBundle:User")->findOneBy(array("username"=>$username));
// Equal to $user = $this->getUser();
$form = $this->createForm(new ChangePasswordType(), $user);
//ChangePasswordType equals the one 'thesearentthedroids' posted
$form->handleRequest($request);
if($request->getMethod() === "POST" && $form->isValid()) {
$manager = $this->getDoctrine()->getManager();
$user->setPassword(password_hash($user->getPassword(), PASSWORD_BCRYPT));
[...]
}
return array(...);
isValid()
函数正在触发UserPassword约束验证器:
The isValid()
function is triggering the UserPassword Constraint Validator:
public function validate($password, Constraint $constraint)
{
if (!$constraint instanceof UserPassword) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword');
}
$user = $this->tokenStorage->getToken()->getUser();
if (!$user instanceof UserInterface) {
throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.');
}
$encoder = $this->encoderFactory->getEncoder($user);
if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
$this->context->addViolation($constraint->message);
}
}
感兴趣的行是:if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt()))
在我的情况下,$user->getPassword()
会将我刚刚在表单中输入的新密码作为我的新密码退还给我.这就是测试始终失败的原因!我不明白为什么令牌存储中的用户与我从数据库中加载的用户之间可能存在连接.感觉这两个对象(一个是MyDatabase,另一个是tokenStorage)共享相同的处理器地址,并且实际上是相同的...
In my case the $user->getPassword()
was giving back the new Password I just entered in the form as my new Password.Thats why the test allways failed!I did not understand why there could be a connection between the User in the tokenStorage and the one that I loaded from my Database.It feels like both Objects (MyDatabase one and the tokenStorage one) share the same processor address and are actually the same...
很奇怪!
我的解决方案是还将ChangePasswordType中的(新)密码字段与EntityMapping分离:请参见
My solution was to also decouple the (new)password field in ChangePasswordType from the EntityMapping: See
->add('currentpassword', 'password', array('label'=>'Current password', 'mapped' => false, 'constraints' => new UserPassword()))
->add('password', 'repeated', array(
'mapped' => false,
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
))
->add('Send', 'submit')
->add('Reset','reset')
兴趣所在的行是'mapped' => false,
这样,在表单中输入的新密码将不会自动映射到给定的$user
实体.相反,您现在需要从form
抓取它.见
By this, the new password entered in the form will not be automatically mapped to the given $user
Entity. Instead you now need to grab it from the form
. See
$form->handleRequest($request);
if($request->getMethod() === "POST" && $form->isValid()) {
$data = $form->getData();
$manager = $this->getDoctrine()->getManager();
$user->setPassword(password_hash($data->getPassword(), PASSWORD_BCRYPT));
$manager->persist($user);
$manager->flush();
}
一些我无法完全理解的问题的解决方法.如果有人能解释数据库对象和security.context对象之间的联系,我将很高兴听到它!
A bit of a workaround for problem what I could not fully understand. If anyone can explain the connection between the Database Object and the security.context Object I'd be glad to hear it!
这篇关于在表单类型中使用Symfony2 UserPassword验证程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!