在本章中,咱们将对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')"/>
这将可以达到咱们想要的效果:容许任何用户访问登陆页而限制站点的其余部分只能是认证用户才能访问。到此为止,已经完成了登陆功能。让咱们看一下要添加退出功能都须要作些什么。