我正在使用FOSUserBundle处理symfony应用程序。如果我没有经过身份验证,我希望在菜单栏中有一个下拉登录表单,它具有与/ login下的完全不同的样式。
我收到'无效的CSRF令牌'。我是symfony2的完全新手,所以也许我犯了一个明显的错误,但我找不到谷歌搜索的解决方案。这就是我的尝试:
控制器:
<?php
namespace RoiRodriguez\CustomUserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\SecurityContext;
class DefaultController extends Controller {
/**
* Para requests internos, renderiza la barra de navegación.
* No tiene ruta.
*/
public function navigationAction() {
$params = array (
'csrf_token' => '',
'last_username' => ''
);
if ($this->container->get ( 'security.context' )->isGranted ( 'IS_AUTHENTICATED_FULLY' )) {
$session = $this->getRequest ()->getSession ();
$params ['last_username'] = (null === $session) ? '' : $session->get ( SecurityContext::LAST_USERNAME );
$params ['csrf_token'] = $this->container->get ( 'form.csrf_provider' )->generateCsrfToken ( 'authenticate' );
}
return $this->render ( 'CustomUserBundle:Default:navigation.html.twig', $params );
}
}
查看:
<ul class="nav navbar-nav navbar-right">
{% if app.user and app.user.isGranted('IS_AUTHENTICATED_FULLY') %}
{% include 'CustomUserBundle:Default:includes/navigation-authenticated.html.twig' %}
{% else %}
{% include 'CustomUserBundle:Default:includes/navigation-notauthenticated.html.twig' with {'csrf_token': csrf_token, 'last_username': last_username} %}
{% endif %}
</ul>
未经过身份验证的模板:
<li><a href="{{ path('fos_user_registration_register') }}">Nueva cuenta</a></li>
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown">Ingresar <b class="caret"></b></a>
<div class="dropdown-menu dd-login-form-container">
<!-- login form -->
<form role="form" method="post"
action="{{ path("fos_user_security_check") }}">
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
......
<button type="submit" class="btn btn-primary">Ingresa!</button>
</form>
<!-- end login form -->
<ul>
<li><a href="{{ path('fos_user_resetting_request') }}">¿Has olvidado
tu contraseña?</a></li>
<li><a href="{{ path('fos_user_registration_register') }}">¿Todavía
no tienes una cuenta?</a></li>
</ul>
</div>
</li>
我缺少什么?另外:这个下拉菜单也在/ login中呈现,在那里生成令牌两次会有什么问题吗?
答案 0 :(得分:12)
我的自定义登录表单给了我同样的问题 - &#39;无效的CSRF令牌&#39; - 我尝试登录的任何时候。在完成FOSUserBundle配置选项(FOSUserBundle Configuration Reference)的文档后,我发现默认情况下捆绑包启用了不同的令牌管理器。所以我转到我的security.yml文件并注释掉为登录表单指定csrf令牌生成器的行。
以下是我的app / config / security.yml文件的横截面,其中配置指定crsf令牌管理器注释掉。
security:
.......
firewalls:
........
vendor:
pattern: ^/vendor
form_login:
provider: fos_userbundle
# csrf_token_generator: security.csrf.token_manager
login_path: vendor_login
check_path: vendor_login_check
logout: true
执行此操作后,我的登录表单开始工作,我可以登录。
答案 1 :(得分:5)
以下是此问题的最佳和最干净的解决方案:将csrf提供程序设置为Twig全局变量:https://stackoverflow.com/a/17233953/1399706
答案 2 :(得分:1)
过去我遇到过同样的问题...
<form action="{{ path('yourRoute') }}" method="post" {{ form_enctype(form) }}>
CSRF令牌无效,因为我没有插入{{ form_enctype(form) }}
你应该看看http://symfony.com/doc/current/reference/forms/twig_reference.html#form-enctype-view因为这种方式很快就会被删除......
答案 3 :(得分:1)
@Roirodriguez,你的代码帮我解决了这个问题。我想你只需要调用render方法而不是include(我的第4步)。
我想在我的标题上做一个简单的登录表单,如果发生任何错误,它会将您重定向到提供反馈的FOSUserBundle正常登录页面。用户通过身份验证后,我想要一个用户名下拉列表,打开时会显示更多选项(注销链接等)
以下是我如何让它发挥作用:
创建了FOSUserBundle的子捆绑包。我创建了一个新的bundle名称UserBundle,然后使用了get parent方法。 link to FOSUserBundle docs
<?php
namespace Me\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class MeUserBundle extends Bundle
{
public function getParent()
{
return 'FOSUserBundle';
}
}
创建模板为此新登录表单和经过身份验证的下拉列表创建新模板
{#loginHorizontal.html.twig#}
{% trans_default_domain 'FOSUserBundle' %}
<div class="nav navbar-nav navbar-right">
<form class="navbar-form navbar-left form-inline" action="{{ path("fos_user_security_check") }}" method="post" role="form" >
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-user" ></i></div>
<input type="text" class="form-control" id="txt_username"
placeholder="{{ 'security.login.username'|trans }}" name="_username"
value="{{ last_username }}" required="required" >
</div>
</div>
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-asterisk" ></i></div>
<input type="password" class="form-control" id="txt_pwd" name="_password" required="required" placeholder="{{ 'security.login.password'|trans }}" />
</div>
</div>
<input type="submit" id="_submit" name="_submit" class="btn btn-primary" value="{{ 'security.login.submit'|trans }}" />
<br />
<div class="checkbox">
<label>
<input type="checkbox" id="remember_me" name="_remember_me" value="on" /> {{ 'security.login.remember_me'|trans }}
</label>
</div>
</form>
</div>
{#authenticadedDropdown.html.twig#}
{% trans_default_domain 'FOSUserBundle' %}
<ul class="nav navbar-nav navbar-right" >
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> welcome, {{ app.user.username }}<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">bla bla</a></li>
<li class="divider"></li>
<li><a href="{{ path('fos_user_security_logout') }}">
{{ 'layout.logout'|trans({}, 'FOSUserBundle') }}
</a></li>
</ul>
</li>
<li></li>
</ul>
覆盖SecurityController并创建操作覆盖控制器并创建一个新的Action,呈现此模板,用于创建和发送变量csrf_token&amp;用户名作为登录参数。
namespace Me\UserBundle\Controller;
use FOS\UserBundle\Controller\SecurityController as BaseController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
class SecurityController extends BaseController
{
/**
* For internal template use: Renders the Horizontal Login ej. Header bar login.
* No routing used.
*/
public function loginHorizontalAction(Request $request)
{
/** @var $session \Symfony\Component\HttpFoundation\Session\Session */
$session = $request->getSession();
// last username entered by the user
$lastUsername = (null === $session) ? '' : $session->get(SecurityContextInterface::LAST_USERNAME);
$csrfToken = $this->container->has('form.csrf_provider')
? $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate')
: null;
$data = array(
'last_username' => $lastUsername,
'csrf_token' => $csrfToken,
);
return $this->container->get('templating')->renderResponse('MeUserBundle:Security:loginHorizontal.html.twig', $data);
}
/**
* For internal template use: Renders the Dropdown after authentication ej. Header bar for user.
* No routing used.
*/
public function authenticatedDropdownAction()
{
$data = array();
return $this->container->get('templating')
->renderResponse('MeUserBundle:Security:authenticatedDropdown.html.twig', $data);
}
}
嵌入控制器操作最后,我通过twig模板嵌入/渲染这个新创建的控制器操作Symfony doc on how to embed controller actions
<div class="navbar-right" >
{% block login %}
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
{% render(controller("MeUserBundle:Security:authenticatedDropdown")) %}
{% else %}
{% render(controller("MeUserBundle:Security:loginHorizontal")) %}
{% endif %}
{% endblock %}
</div>
我知道你的帖子已经有一段时间了,但希望这会有所帮助。
干杯, 潘乔
答案 4 :(得分:0)
我在覆盖登录模板时使用symfony 4和FOSUserBundle搜索解决方案时遇到了这个问题。
对我来说,以下工作有效:
在我发现的login_content.html.twig中:
{% if csrf_token %}
<input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
{% endif %}
我已将其替换为:
{% if csrf_token('authenticate') %}
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
{% endif %}
注意:额外的“('authenticate')”
现在我得到了crsf令牌。在此之前是空的。
希望这对其他人也有帮助。