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

相關文章
相關標籤/搜索