symfony2 登錄驗證(轉自http://www.newlifeclan.com/symfony/archives/300)


注意:如果你需要為存儲在某種數據庫中的用戶做一個登錄表單,那么你應該考慮使用FOSUserBundle,這有助於你建立你的User對象,還為您提供了常見的登錄、注冊、忘記密碼的路由和控制器。

在此文章中,將構建一個傳統的登錄表單。當然,當用戶登錄時,你可以從數據庫或者任何地方加載用戶。

首先,啟用防火牆下表單登錄

# 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沒有默認值

現在,當安全系統啟動認證過程,它會讓用戶跳轉到登錄表單 /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):

annotations

// 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表單:

// 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都有介紹。

不要讓這個控制器迷惑你。你看到當用戶提交表單的這一刻,security系統會自動處理表單提交到這個控制器。如果用戶提交了一個無效的用戶名和密碼,該控制器可以從security系統中讀出表單提交的錯誤,以便把他顯示給用戶。

換句話說,你的工作是顯示登錄表單和任何可能發生的登錄錯誤,但是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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM