在本章中,咱們將對JBCP Pets在線商店增長一些功能,這些新功能可以爲用戶提供更愉悅和可用的用戶體驗,同時提供一些對安全系統很重要的功能。html
在本章中,咱們將要:java
按照你的意願自定義登陸和退出頁面,並將它們與標準的Spring web MVC的控制器相關聯;web
使用remember me功能爲用戶提供便利,並理解其背後的安全含義;spring
構建用戶帳號管理功能,包括修改密碼以及密碼遺忘找回功能。express
你可能還記得在前一章中,咱們使用了Spring Security的security命名空間的基本配置功能。這爲咱們提供了基本的登陸、認證和受權功能,可是這確定沒有到達產品質量的要求。在咱們向老闆彙報進度前,要添加的一個很重要的加強功能就是使得登陸界面在展示和行爲上與咱們在線應用的其餘地方保持一致。瀏覽器
回憶一下如今的登陸界面大體以下所示:安全
自動配置並無爲咱們提供不少其餘的功能,如爲登陸頁面添加樣式。咱們要爲站點增長如下的功能:app
擁有頁頭、頁腳以及與JBCP Pets樣式一致的登陸頁;jsp
容許用戶退出的連接post
容許用戶修改密碼的頁面。
登陸和退出的流程應該以下圖所示:
咱們將會經過一系列的練習來開發完善這個站點的結構。當開發登陸和退出功能時,咱們將會講解所作的內容,因此當咱們須要擴展站點的基本功能時,可以對於咱們構建的內容有一個清晰的理解。
實現自定義登錄頁面
首先,咱們須要一個集成於咱們系統的登陸頁來替代默認的Spring Security登陸頁。須要的登陸流程以下圖所示:
咱們須要添加一個Spring MVC的控制器來實現登陸功能,以及之後的退出功能。JBCP Pets站點使用Spring MVC基於註解的機制來實現控制器與站點路徑和資源的配置。讓咱們在包下com.packtpub.springsecurity.web.controller建立一個名爲LoginLogoutController的controller,幷包含如下的內容:
// imports omitted @Controller public class LoginLogoutController extends BaseController{ @RequestMapping(method=RequestMethod.GET,value="/login.do") public void home() { } }
能夠看到,咱們添加了一個很是簡單的controller,並將其惟一的方法匹配至/login.do這個URL地址。這是咱們編寫簡單的自定義登陸頁所要作的所有事情,這將替代Spring Security基本配置中爲咱們添加的登陸頁。BaseController基類在第二章:Spring Security起步的代碼中已經添加,它提供了一個便利的地方咱們能夠添加應用中全部controller都能用到的方法。
/login.do引用將會致使咱們在WEB-INF/dogstore-servlet.xml配置的Spring MVC view resolver去/WEB-INF/views目錄下尋找名爲login.jsp的JSP文件。讓咱們添加一個包含登陸form的簡單JSP,它將被Spring Security識別和使用。
在第二章中咱們已經學到,爲了保證接下來的行爲可以被正確的執行,登陸的form中有兩個重要的元素必需要被正確的設置:
Form action必須與UsernamePasswordAuthenticationFilter過濾器的action的配置相一致。默認的form action是j_spring_security_check;
用戶名和密碼的表單域要與servlet的標準相一致。默認j_username和j_password是文本域的名字。
咱們同時會在這個JSP中包含站點的頁頭和頁腳(本章的示例代碼中添加了這部分,可是在本書的內容中沒有進行羅列,由於它們在這裏並非闡述的重點所在)。這些完成後,獲得一個簡單的JSP:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <jsp:include page="common/header.jsp"> <jsp:param name="pageTitle" value="Login"/> </jsp:include> <h1>Please Log In to Your Account</h1> <p> Please use the form below to log in to your account. </p> <form action="j_spring_security_check" method="post"> <label for="j_username">Login</label>: <input id="j_username" name="j_username" size="20" maxlength="50" type="text"/> <br /> <label for="j_password">Password</label>: <input id="j_password" name="j_password" size="20" maxlength="50" type="password"/> <br /> <input type="submit" value="Login"/> </form> <jsp:include page="common/footer.jsp"/>
須要注意的是,必須使用post方式的form提交,不然UsernamePasswordAuthenticationFilter會拒絕登陸請求。
最後,咱們還須要Spring Security的自動配置來引用咱們新的登陸頁面。若是你在此時火燒眉毛想看一下效果的話,咱們實際上只是爲應用增長了一個新的工做頁面。按照上面的流程並輸入如下的地址http://localhost:8080/JBCPPets/login.do,看看發生了什麼。
什麼?你是否發現你的請求首先被Spring Security攔截了(被重定向到spring_security_login)而且可以看見那個登陸的form?這是由於Spring Security依舊指向了DefaultLoginPageGeneratingFilter生成的默認登陸頁。一旦你經過了這個過濾器生成的默認登陸頁,你纔可以看到新的自定義登陸頁。最後一步就是要移除默認頁並使用咱們的登陸form做爲登陸頁。
按照第一感受,貌似咱們只須要配置Spring Security的配置文件中的<form-login>元素並添加login-page命令,大體以下所示:
<http auto-config="true" use-expressions="true"> <intercept-url pattern="/*" access="hasRole('ROLE_USER')"/> <form-login login-page="/login.do" /> </http>
如今,啓動應用並輸入首頁地址(http://localhost:8080/JBCPPets/home.do)。若是你使用的IE瀏覽器,你會發現頁面根本沒有渲染,可是頁面的彷佛在不停的加載。讓咱們切換到Mozilla Firefox並訪問一樣的地址。在Firefox下,你可以看到更多的信息,以下所示:
產生這樣的問題是由於咱們的URL攔截規則:
<intercept-url pattern="/*" access="hasRole('ROLE_USER')"/>
這將要求訪問全部匹配/*的URL(這將匹配應用的全部頁面,包括咱們新的登陸頁)都須要擁有ROLE_USER角色。下面的圖展示了發生了什麼事情:
(其實上面發生了反覆請求登陸頁的狀況,死循環了——譯者注)
咱們須要修改認證規則來容許匿名用戶可以訪問登陸頁。
【對於全部給定的URL請求,Spring Security按照自頂向下的順序評估認證規則。第一個匹配URL模式的規則將會被使用。這意味着你的受權規則將要按照最特殊的到最不特殊的規則來進行排列。這在開發複雜的規則集合時將會很是重要,由於開發人員常常會感到迷惑,由於他們有時會搞不清到底哪一個規則會生效。記住自頂向下順序,你將可以很容易地在任何場景下找到正確的對應規則。】
由於咱們是要添加一個更特殊的規則,因此咱們須要將其添加在列表的頂部。咱們最終會獲得以下的規則設置:
<intercept-url pattern="/login.do" access="permitAll"/> <intercept-url pattern="/*" access="hasRole('ROLE_USER')"/>
這將可以達到咱們想要的效果:容許任何用戶訪問登陸頁而限制站點的其餘部分只能是認證用戶才能訪問。到此爲止,已經完成了登陸功能。讓咱們看一下要添加退出功能都須要作些什麼。