symfony2 登陆验证(转自http://www.newlifeclan.com/symfony/archives/300)

注意:若是你须要为存储在某种数据库中的用户作一个登陆表单,那么你应该考虑使用FOSUserBundle,这有助于你创建你的User对象,还为您提供了常见的登陆、注册、忘记密码的路由和控制器。php

在此文章中,将构建一个传统的登陆表单。固然,当用户登陆时,你能够从数据库或者任何地方加载用户。html

首先,启用防火墙下表单登陆数据库

# app/config/security.yml
security:
    # ...
 
    firewalls:
        default:
            anonymous: ~
            http_basic: ~
            form_login:
                login_path: /login
                check_path: /login_check

这个login_path和check_path也能够是路由名称(但不能有强制通配符例如 /login/{foo})这里foo没有默认值api

如今,当安全系统启动认证过程,它会让用户跳转到登陆表单 /login。你的工做是实现这个登陆表单视觉。首先,建立一个新的SecurityController在bundle中:安全

// src/AppBundle/Controller/SecurityController.php
namespace AppBundle\Controller;
 
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
 
class SecurityController extends Controller
{
}

下一步建立两个路由:分别是刚才form_login下的设置的两个路径(/login和/login_check):app

annotationspost

// src/AppBundle/Controller/SecurityController.php
 
// ...
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 
class SecurityController extends Controller
{
    /**
     * @Route("/login", name="login_route")
     */
    public function loginAction(Request $request)
    {
    }
 
    /**
     * @Route("/login_check", name="login_check")
     */
    public function loginCheckAction()
    {
        // this controller will not be executed,
        // as the route is handled by the Security system
    }
}

很是好!下一步,你要去添加loginAction的逻辑,并把须要的渲染到login表单:this

// src/AppBundle/Controller/SecurityController.php
 
public function loginAction(Request $request)
{
    $authenticationUtils = $this->get('security.authentication_utils');
 
    // get the login error if there is one
    $error = $authenticationUtils->getLastAuthenticationError();
 
    // last username entered by the user
    $lastUsername = $authenticationUtils->getLastUsername();
 
    return $this->render(
        'security/login.html.twig',
        array(
            // last username entered by the user
            'last_username' => $lastUsername,
            'error'         => $error,
        )
    );
}

 这个security.authentication_utils服务和AuthenticationUtils类在symfony2.6都有介绍。url

不要让这个控制器迷惑你。你看到当用户提交表单的这一刻,security系统会自动处理表单提交到这个控制器。若是用户提交了一个无效的用户名和密码,该控制器能够从security系统中读出表单提交的错误,以便把他显示给用户。spa

换句话说,你的工做是显示登陆表单和任何可能发生的登陆错误,可是security系统自己负责检查提交的用户名和密码并认证用户。

最后,建立模版:

{# app/Resources/views/security/login.html.twig #}
{# ... you will probably extends your base template, like base.html.twig #}
 
{% if error %}
    <div>{{ error.messageKey|trans(error.messageData) }}</div>
{% endif %}
 
<form action="{{ path('login_check') }}" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" value="{{ last_username }}" />
 
    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />
 
    {#
        If you want to control the URL the user
        is redirected to on success (more details below)
        <input type="hidden" name="_target_path" value="/account" />
    #}
 
    <button type="submit">login</button>
</form>

这个传入到模版的错误变量是一个AuthenticationException它包含不少信息-一些敏感信息-关于认证失败信息,因此你要明智的使用它。

 

要实现这些东西,要注意这几个要求:

 

  • 该表单必须提交到/login_check,由于你在security.yml的form_login健中配置的
  • 这个用户名必定要name为_username而且password必定要name为_password。

 

其实全部的这些均可以配置到form_login健下,请查看 form登陆配置

此登陆表单目前没有使用CSRF攻击。若是须要请阅读 Using CSRF Protection in the Login Form 。

就是这样!当您提交表单,security系统会自动检查用户的凭证,验证用户或向用户发送错误信息在登录表单。

回顾整个过程:

1.用户试图访问被保护的资源。

2.防火期启用认证过程将用户重定向到登陆表单(/login)

3.这个例子中,经过路由(route)和控制器(controller)来显示登陆表单。

4.用户提交登陆表单到 /login_check;

5.security系统截取请求,检查用户提交的凭据,验证他们是否正确,若是他不是系统容许的,页面会从新跳转到表单。

 

成功后,重定向

若是提交的凭证是正确的,该用户会被从新定向到请求的原始页面(如/admin/foo)。若是用户最初直接进入登陆页面,它须要跳转到首页。这些都是能够设定的,而且容许你指定到一个指定的url上。

更多细节,请参阅 How to Customize your Form Login

 

避免常见问错误

在设置表单时应该注意一些常见的陷阱。

1.建立正确的路由

首先,确保你已经定义了正确的/login和/login_check,他们应该和你配置的login_path和check_path是同样的。 若是你配置错误他会重定向到一个404页面,而不是登陆页面,或者会出现提交表单不执行任何操做(你会一遍又一遍的看到登陆表单)。

2.确保登陆页面能够访问

此外,要确保登陆页面匿名用户能够访问。例如,下面的配置-ROLE_ADMIN角色用于全部的URL(包括 /login),将会出现重定向循环:

# app/config/security.yml
 
# ...
access_control:
    - { path: ^/, roles: ROLE_ADMIN }

添加access_control中添加一个 /login/*,而且指定一个任何身份均可以进入的角色。

# app/config/security.yml
 
# ...
access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/, roles: ROLE_ADMIN }

另外,若是您的防火墙没有容许匿名用户(没有anonymous 键),你须要去建立一个特殊的防火墙,容许匿名用户登陆:

# app/config/security.yml
 
# ...
firewalls:
    # order matters! This must be before the ^/ firewall
    login_firewall:
        pattern:   ^/login$
        anonymous: ~
    secured_area:
        pattern:    ^/
        form_login: ~

 3.确保 /login_check 位于防火墙的后面

确保你的check_path的url(如 /login_check)在表单登陆防火墙里(例如本例,单一的防火墙匹配全部URL,包含/login_check)。若是/login_check不匹配路由,你会收到一个Unable to find the controller for path “/login_check”的异常。

4.多个防火墙不共享相同的Security内容

若是你使用多个防火墙而且你进行认证了一个防火墙,其余的防火墙就不会对此作自动认证了。不一样的防火墙,就像不一样的安全系统。要作到这一点,你就必需要明确指定不一样防火墙下相同的 Firewall Context  。但大多数应用,有一个主要的防火墙就足够了。

5.路由错误不受防火墙限制

Security已经把路由里的404页面设置成了不受防火墙限制。这意味着在这些页面上,你不能检测Security甚至访问用户对象。请查看 How to Customize Error Pages

相关文章
相关标签/搜索