注意:若是你須要爲存儲在某種數據庫中的用戶作一個登陸表單,那麼你應該考慮使用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。它包含不少信息-一些敏感信息-關於認證失敗信息,因此你要明智的使用它。
要實現這些東西,要注意這幾個要求:
其實全部的這些均可以配置到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