《Spring Security3》第三章第一部分翻译(转载)

第三章    增强用户体验

在本章中,我们将对 JBCP Pets 在线商店增加一些功能,这些新功能能够为用户提供更愉悦和可用的用户体验,同时提供一些对安全系统很重要的功能。

在本章中,我们将要:

l   按照你的意愿自定义登录和退出页面,并将它们与标准的 Spring web MVC 的控制器相关联;

l   使用 remember me 功能为用户提供便利,并理解其背后的安全含义;

l   构建用户账号管理功能,包括修改密码以及密码遗忘找回功能。

自定义登录页

你可能还记得在前一章中,我们使用了 Spring Security security 命名空间的基本配置功能。这为我们提供了基本的登录、认证和授权功能,但是这肯定没有到达产品质量的要求。在我们向老板汇报进度前,要添加的一个很重要的增强功能就是使得登录界面在展现和行为上与我们在线应用的其他地方保持一致。

回忆一下现在的登录界面大致如下所示:

 

自动配置并没有为我们提供很多其他的功能,如为登录页面添加样式。我们要为站点增加以下的功能:

l   拥有页头、页脚以及与 JBCP Pets 样式一致的登录页;

l   允许用户退出的链接

l   允许用户修改密码的页面。

登录和退出的流程应该如下图所示:


 

我们将会通过一系列的练习来开发完善这个站点的结构。当开发登录和退出功能时,我们将会讲解所做的内容,所以当我们需要扩展站点的基本功能时,能够对于我们构建的内容有一个清晰的理解。

实现自定义的登录页

首先,我们需要一个集成于我们系统的登录页来替代默认的 Spring Security 登录页。需要的登录流程如下图所示:



 

实现登录的 controller

我们需要添加一个 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 都能用到的方法。

添加登录 JSP

/login.do 引用将会导致我们在 WEB-INF/dogstore-servlet.xml 配置的 Spring MVC view resolver /WEB-INF/views 目录下寻找名为 login.jsp JSP 文件。让我们添加一个包含登录 form 的简单 JSP ,它将被 Spring Security 识别和使用。在第二章中我们已经学到,为了保证接下来的行为能够被正确的执行,登录的 form 中有两个重要的元素必须要被正确的设置:

l  Form action 必须与 UsernamePasswordAuthenticationFilter 过滤器的 action 的配置相一致。默认的 form action j_spring_security_check

l  用户名和密码的表单域要与 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 以使用我们的 Spring MVC 登录页

按照第一感觉,貌似我们只需要配置 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')"/>

这将能够达到我们想要的效果:允许任何用户访问登录页而限制站点的其他部分只能是认证用户才能访问。到此为止,已经完成了登录功能。让我们看一下要添加退出功能都需要做些什么。

猜你喜欢

转载自kongcodecenter.iteye.com/blog/1320019