2013-12-08 61 views
4

我正在使用FOSUserBundle开发symfony应用程序。如果我没有通过身份验证,我希望在菜单栏中有一个下拉式登录表单,它具有与/ login下的完全不同的样式。我自己的登录表单上的无效CSRF令牌

我收到'无效的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> 

我在想什么?另外:这个下拉菜单也得到渲染内/登录,我会有任何麻烦生成令牌两次?

+0

我非常新的Symfony的,但你可以尝试设置csrf_token为假,可能是它会奏效。 –

回答

1

@Roirodriguez,你的代码可以帮助我解决这个问题。我想你只需要调用渲染方法而不是包含(我的第4步)。

我想在我的标题上做一个简单的登录表单,如果发生任何错误,它会将您重定向到提供反馈的FOSUserBundle正常登录页面。用户在通过身份验证后,我想用的用户名,打开的时候更多的选择会showup(注销链接等)下拉

这里是我设法得到它的工作:

  1. 创建一个FOSUserBundle的儿童套装。我创建了一个新的包名称UserBundle,然后使用get父级方法。 link to FOSUserBundle docs

    <?php 
    namespace Me\UserBundle; 
    use Symfony\Component\HttpKernel\Bundle\Bundle; 
    class MeUserBundle extends Bundle 
    { 
        public function getParent() 
        { 
         return 'FOSUserBundle'; 
        } 
    } 
    
  2. 创建模板创造了这个新的登录表单的新模板,并通过身份验证的下拉

    {#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> 
    
  3. Overided的SecurityController和创造行动在此改变控制器和创建一个新的动作该模板创建并发送变量csrf_token &用户名作为登录参数。

    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); 
        } 
    } 
    
  4. 嵌入控制器动作最后我通过树枝模板嵌入式/ renderes这个新创建的控制器的作用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

我的自定义登录表单是给我同样的问题, - '无效的CSRF令牌' - 任何时候我尝试登录。在阅读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 

这样做了以后,我的登录表单开始工作,我可以登录。