身份认证管理
使用Acegi保护应用程序的第一步是根据用户提供的认证信息进行身份认证,以确定用户的身份,获取对应的权限信息,准备好Authentication。通过认证的Authentication拥有权限信息,它是Acegi进行后续安全对象访问安全控制的依据。
Acegi对所有类型安全对象的访问控制机制基本相同:判断Authentication是否已经包含访问安全对象所需的权限。但Acegi进行身份认证的方式则多姿多彩、五花八门,身份认证方式的多样性源于认证系统的多样性。由于篇幅所限,不可能面面俱到的逐一讲解所有的认证方式,我们将以最常见的基于数据库的认证方式并对其它的认证方式进行简单的概述。
基于内存存储用户信息的身份认证
如果你开发的系统仅有少数几个固定的用户,且用户信息管理的功能很简单,这时你可以将用户直接保存在配置文件中,在系统启动将使用户信息常驻于内存中。下面,我们就从这个最简单的身份认证方式出发开始学习Acegi实际应用的征程。
代码清单 3 applicationContext-acegi-plugin.xml
身份认证过滤器
<beans> <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> … /**=authenticationProcessingFilter ①使用认证处理过滤器处理匹配的URL </value> </property> </bean> <bean id="authenticationProcessingFilter" ②认证处理过滤器 class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> ②-1过滤器处理的URL <property name="filterProcessesUrl" value="/j_acegi_security_check"/> <property name="defaultTargetUrl" value="/main.jsp"/> ②-2认证成功后转向的URL ②-3认证失败后转向的URL <property name="authenticationFailureUrl" value="/index.jsp?login_error=1"/> </bean> </beans>
首先,在①处通过FilterChainProxy定义了仅包含一个authenticationProcessingFilter的过滤器链。这个过滤器链匹配于所有URL的请求,换句话说,authenticationProcessingFilter有机会对所有URL请求进行拦截处理,而在这所有这些URL请求中,究竟哪个URL请求才是用户身份认证的请求呢?如果你心中也拥有这个疑问,则说明你正走在正确的理解问题的思路上。
authenticationProcessingFilter在②-1、2、3处,定义了一些URL,它们分别对应身份认证请求的URL、认证成功后转向的URL以及认证失败后转向的URL。其中②-1处的filterProcessesUrl属性表示这个URL是用户提交身份信息并要求进行身份认证的HTTP请求(一般是一个包含用户名/密码的表单HTTP POST请求),“/j_acegi_security_check”是默认的设置,之所以在此显式给出设置值,是为了说明你可以根据实际需要进行调整。
现在,authenticationProcessingFilter已经知道了申请进行用户身份认证URL,但它如何知道这个HTTP请求分别通过什么参数代表用户名和密码呢?Acegi框架规定必须使用j_username和j_password作为用户名和密码的HTTP参数名。这两个参数名是固定的,Acegi不允许对此进行配置,不过这种约定俗成而非事事配置的风格正渐渐成为流行的设计模式。
我们来看一下提供用户名/密码输入表单的登录页面:
代码清单 4 index.jsp:登录页面
<%@ page contentType="text/html;charset=UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <body> <c:if test="${not empty param.login_error}"> ① <font color="red">用户名或密码错误。</font> </c:if> ②处理用户身份认证服务所对应的URL <form name="form1" method="post" action="<c:url value="/j_acegi_security_check"/>"> 用户名:<input type="text" name="j_username"/><br/>③用户名的参数名 密 码:<input type="password" name="j_password"/><br/>④用户密码的参数名 <input type="submit" value="登录"/> </form> </body> </html>
②处对应代码清单 3中②-1处的设置值,它表示处理用户身份认证服务所在的URL,而③和④是Acegi规定的承载用户名、密码的参数名。当这个表单提交后authenticationProcessingFilter将从请求中抽取j_username和j_password参数的值,两者组成了代表请求认证的用户信息,Acegi使用这个信息构造Authenticaion实例,并封装成SecurityContext放入到SecurityContextHolder中,然后启动用户身份认证的流程。当认证成功后,页面转向代码清单 3中②-2处所定义的/main.jsp,如果认证失败则转向代码清单 3中②-3处所定义的/index.jsp?login_error=1。由于登录失败后也转向index.jsp页面,所以代码清单 4的①处专门对此进行了处理,当发现请求参数包含login_error时,打出一行提示登录失败的信息。
现在,我们已经了解了authenticationProcessingFilter从何处获取需要进行认证的用户信息,并对认证成功和失败后的转向进行了定义。那么authenticationProcessingFilter究竟如何对用户信息(用户名/密码)的合法性进行认证呢?
authenticationProcessingFilter其实只负责获取需要认证的用户信息并根据结果完成页面转向,它相当于一个客户受理的窗口,真正的用户身份认证工作则交由后台的AuthenticationManager完成。