在过去的几个小时里,我一直在尝试使用Symfony表单生成器构建登录表单。
据我所知,问题是表单生成器创建表单formName[fieldName]的字段名(例如login[_username]),而安全组件则查找"平面"字段名(如_username)。这会导致CSRF在提交时失败。
我一直无法找到任何方法来强制表单生成器生成平面字段名称。
有人知道使用表单生成器构建登录表单的方法吗?这可能吗?
谢谢。
------------响应Cerad回答的更新------------------
Cerad。感谢您的回复和链接。
我已将我的安全性yml更新为:
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
provider:
form_login:
check_path: userLoginCheck
login_path: userLogin
always_use_default_target_path: true
default_target_path: /
username_parameter: login[email]
password_parameter: login[password]
csrf_parameter: login[_token]
intention: authenticate
csrf_provider: form.csrf_provider
logout: true
anonymous: true
switch_user: { role: ROLE_SUPER_ADMIN }
我所呈现的形式与您的示例中有所不同
我正在使用一个表单类型,并在我的控制器中调用$this->createForm()
呈现的表单如下所示:
<form name="login"
method="post"
action="/user/loginCheck"
class="dplhUser"
novalidate="novalidate">
<div id="login">
<div class="formRow">
<label for="login_email"
class="required">Email:</label>
<input type="text"
id="login_email"
name="login[email]"
required="required"/>
</div>
<div class="formRow">
<label for="login_password"
class="required">Password:</label>
<input type="password"
id="login_password"
name="login[password]"
required="required"/>
</div>
<input type="hidden"
id="login__token"
name="login[_token]"
value="ij3CcnLiHzeLrNUDnxXtdExcPvGkgusIEriYmnZmgy8"/></div>
<label for="submit"></label>
<input type="submit"
name="submit"
Value="Login"/>
</form>
名称属性与现在处于security.yml中的名称属性相匹配。
我清除了缓存并删除了会话cookie。仍有CSRF故障。
表单构造:
class LoginType extends AbstractType
{
public function buildForm( FormBuilderInterface $builder, array $options )
{
$builder
->add( 'email', null, ['mapped' => false] )
->add( 'password', 'password', ['mapped' => false] );
}
public function getName()
{
return 'login';
}
public function setDefaultOptions( OptionsResolverInterface $resolver )
{
$resolver->setDefaults( ['intention' => 'authentication'] );
}
}
我认为您已经接近了,但您没有尝试更改表单字段名称,而是更改了安全系统所期望的名称。大部分内容都记录在参考部分中,但要把它们放在一起确实需要一些时间。
http://symfony.com/doc/current/reference/configuration/security.html
# security.yml
form_login:
provider: cerad_tourn_account_user_provider
login_path: cerad_tourn_account_user_login
check_path: cerad_tourn_account_user_login_check
default_target_path: cerad_tourn_home
# This matches your form element names
username_parameter: cerad_tourn_account_user_login[username]
password_parameter: cerad_tourn_account_user_login[password]
csrf_parameter: cerad_tourn_account_user_login[_token]
csrf_provider: form.csrf_provider
intention: authenticate
protected function createFormForModel($model)
{
/* ======================================================
* Start building
*/
$formOptions = array(
'cascade_validation' => true,
'intention' => 'authenticate', // Matches security.yml
'csrf_protection' => true,
);
$constraintOptions = array();
// The name here matches your security file
$builder = $this->get('form.factory')->createNamed(
'cerad_tourn_account_user_login',
'form',$model,$formOptions);
$builder->add('username','text', array(
'required' => true,
'label' => 'Email',
'trim' => true,
'constraints' => array(
new UsernameOrEmailExistsConstraint($constraintOptions),
),
'attr' => array('size' => 30),
));
$builder->add('password','password', array(
'required' => true,
'label' => 'Password',
'trim' => true,
'constraints' => array(
new NotBlankConstraint($constraintOptions),
),
'attr' => array('size' => 30),
));
$builder->add('remember_me','checkbox', array('label' => 'Remember Me'));
// Actually a form
return $builder;
}
模板没有什么特别之处,form_rest(form)将输出csrf _token。
上面没有提到的实现这一目标的缺失部分:
这是控制器和你必须输入的信息:
public function loginAction()
{
$authenticationUtils = $this->get('security.authentication_utils');
$form = $this->createForm(new LoginType(), array(), array(
'action' => $this->generateUrl('login_check')));
return $this->render('AppBundle:Security:login.html.twig', array(
'last_username' => $authenticationUtils->getLastUsername(),
'error' => $authenticationUtils->getLastAuthenticationError(),
'form' => $form->createView()
));
}
现在,您可以使用CreateForm()构建登录!:-)