有关本系列教程的目录,源代码以及相关说明,请参考 附录
在我们的报名系统中,有一个领域没有涉及,那就是认证授权。我们允许用户自由地报名,自由地添加课程,这显然不适用于实际的项目。我们需要调整一下添加待报名课程的功能,要求这一功能仅管理员可以在授权登录后进行使用。在这一章中,您将学习如何使用Spring Security模块来实现这一目的。
Spring Security介绍
Spring Security是Spring框架的一个组成部分,它的前身叫做Acegi Security。有关它的历史,在这里简单介绍一下。Acegi Security项目于2003年启动,那个时候,在Spring项目的邮件列表中,有人提出要求,问是否能在Spring工具包中添加一个处理认证授权的模块。由于那个时候Spring项目才刚刚开始,规模也很小,虽然大家都认为这个很重要,但无法花大精力去做。因此,Spring的开发小组开始默默地做出一个简单的认证授权模块,但没有把它开放给用户去试。就这样,随着用户对这方面的需要增多,在2004年3月,这个项目开始启动了。随着Acegi Security项目的不断发展,在2007年末,Acegi Security正式更名为Spring Security。
那么Sping Security到底为我们带来些什么呢?可以说,Spring Security既是一个认证模块,又是一个授权模块。认证和授权是安全领域两个非常重要的概念。认证即Authentication,它指对用户身份的确认;授权即Authorization,它是指当一个用户通过认证后,判断这个受信任的用户是否有权利去进行某种操作。举个例子来说,买票进入游乐园是认证过程,进入游乐园后,18岁以上玩家才能玩彩弹射击,这是个授权过程。你的票是认证凭据。而18岁以上这个条件则是一个授权标准。
随着安全领域不断标准化,认证与授权的两个概念也区分得越来越明确。在网上,您如果对安全领域比较关注,经常会看到A1、A2的说法。A1就是指认证,而A2则是指授权。常用的说法还有AuthN/AuthZ(认证/授权)及Au/Az(认证/授权)。
言归正传,Spring Security就是一个认证/授权模块,它同时对这两块提供宣告式管理,使认证授权过程从项目的逻辑代码中分离出来。在报名系统中,我们将使用Spring Security对整个系统进行保护。首先,只有tom这个用户可以添加待报名课程;其次,只有peter这个用户可以使用搜索报名信息的功能。这就是我们的业务需求,下面我们来把它分解成可以进行实际制作的设计方案 1 。
1 不知道您注意到没有,本系列文章讲设计方法与讲实际技术的比重是差不多的。如果没有好的设计,再好的技术也发挥不出它的优势。因此,在这里还需要再唐僧一番:请您时刻牢记OCP法则,MVC设计模式。
系统设计
我们要为报名系统添加安全层面,要达到的效果是:
从设计的角度来讲,我们可以把这个需求分解如下:
Spring Security的安装
安装Spring Security需要在Maven的pom.xml中添加dependency:
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>2.0.3</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>2.0.3</version> </dependency>
实际制作
为了达到上面的设计要求,我们需要做的就是在项目中添加一个配置文件。您一定会产生疑问,只需要一个配置文件?没错,就是这么简单。我们来看看这个配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd"> <!-- Configure Spring Security --> <http auto-config="true"> <intercept-url pattern="/addClazz.html*" access="ROLE_CLASS_MANAGER" /> <intercept-url pattern="/search.html*" access="ROLE_SEARCHER" /> </http> <authentication-provider> <password-encoder hash="md5" /> <user-service> <user name="tom" password="d077f244def8a70e5ea758bd8352fcd8" authorities="ROLE_CLASS_MANAGER" /> <user name="peter" password="06d80eb0c50b49a509b49f2424e8c805" authorities="ROLE_SEARCHER" /> </user-service> </authentication-provider> </beans:beans>
配置文件非常简单,也比较直白,但为了方便您理解,我们还是在下面进行一下逐行的说明:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" ... xmlns:tx="http://www.springframework.org/schema/tx" ... http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> ... <tx:annotation-driven transaction-manager="transactionManager" /> ... </beans>
由于annotation-driven这个bean是定义在 http://www.springframework.org/schema/tx 中的,由于这个配置文件中有用到了很多命名空间中定义的bean 2 ,因此如果要正确引用到每个空间中的bean,必须明确地指定这个bean所在的命名空间。而命名空间需要自己来起个名字。在这个例子中,我们将 http://www.springframework.org/schema/tx 放在"tx"这个名字的空间里。而我们如果要引用 http://www.springframework.org/schema/tx 中的bean,如annotation-driven,就必须写成
2 这就相当于一个代码中引用了很多package中的类
<beans:beans>
可以把它声明成本文件的唯一空间,我们就不用再指定前缀了,直接使用security中的bean即可。我们在这里探讨了一下内部原理,如果您不是很理解也没有关系,这并不影响您的使用。我们不一定非得f会做发动机才能学开车,因此请您继续往下看。
/addClazz.html*
匹配根目录下 addClazz.html 为开头的各种URL,如 addClazz.html?xxx=yyy ,这些都匹配 addClazz.html** 。再举一个例子:
/aaa/*
这个匹配 /aaa/ 目录下的所有URL地址,如: /aaa/b.html , /aaa/a.html , /aaa/a.html?xxx=yyy 等。
再举一个例子:
/aaa/**
这个匹配 /aaa/ 目录下所有的URL地址,及/aaa所有下一级目录的地址,比如 /aaa/bbb/b.html ,就可以匹配上,而 /aaa/** 只能匹配 /aaa/ 本级URL地址。
再来一个例子看看:
/*/aaa/**/*.html*
这个匹配一级目录随意,二级目录必须为aaa,后续任意多级目录中 *.html 的URL地址。回来看看我们的定义,其中 addClazz.html 只有具备ROLE_CLASS_MANAGER角色的用户才能使用。而 search.html 则需要用户具备ROLE_SEARCHER的角色。
3 md5转码后的值
做好配置后,把它加载进web.xml:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> ... /WEB-INF/security.xml </param-value> </context-param> ... <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ...
这里有一点需要注意的是,Spring Security是以Filter的机制来进行工作的。DelegatingFilterProxy负责接收所有的HTTP请求,请求进来后,security.xml中的配置生效,如果URL匹配策略中需要进行鉴权的点,那么配置中的内容就会开始生效。
接下来我们就来看看配置完的效果。
成果
我们现在试着访问 http://127.0.0.1:8080/reg/search.html ,这时系统自动发现我们没有登录,自动将我们转向登录页面,如下图所示:

现在您可能会觉得有些奇怪,这个登录界面是怎么出来的?还记得security.xml中的配置吗:
<http auto-config="true">
auto-config帮我们做了很多事情,这其中就包括提供登录界面。我们如果对登录界面有特殊需要,那么就可以去掉auto-config,自己定制各种细节,包括登录页面。在这一章先讲解最简单的方法,使用自动提供的登录页面。我们使用peter账号进行认证登录,如下图所示:

认证通过后,Spring会进行鉴权,判断peter是否有访问search.html的权限,根据配置中的定义,peter便可以使用search.html提供的搜索功能了。如果peter想使用不属于他的addClazz.html,结果会是怎么样?效果如下图所示:

答案是鉴权失败。让我们来分析一下这个结果:首先,由于我们已经用peter登录了,因此,认证过程通过,系统不再弹出登录界面。其次,由于peter不具有访问addClazz.html的权限,仅tom具备这一权力。因此,系统弹出鉴权失败的界面。
视图层鉴权
所谓视图层鉴权,就是在JSP页面中添加Spring Security的控制标签,对页面中的某一部分实行特定的鉴权要求定制。在页面中的鉴权可以说比基于URL的方式颗粒度更细一些。因为URL的匹配方式就相当于整页面的匹配,f而基于页面标签的匹配,可以为页面中某一部分进行鉴权配置。我们在这一节中主要介绍两个Spring Security提供的页面标签:
<authz:authentication>
以及
<authz:authorize>
其中,第一个是用于在页面中显示用户鉴权信息的。第二个则是控制鉴权。我们来讲解一下它们的使用方法。实际上非常简单,比如我们希望控制页面中的某一块,只有具备ROLE_ADMIN角色的用户才能看到,那么就这样:
<authz:authorize ifAllGranted="ROLE_ADMIN"> <h1>Hello, World!</h1> </authz:authorize>
如果希望具备ROLE_ADMIN或ROLE_USER的用户能够看到,那么就:
<authz:authorize ifAnyGranted="ROLE_ADMIN,ROLE_USER"> <h1>Hello, World!</h1> </authz:authorize>
如果希望角色为ROLE_USER的人不能看到某段页面,那么就:
<authz:authorize ifNotGranted="ROLE_USER"> <h1>Hello, World!</h1> </authz:authorize>
这些标记中的配置项可以混用,实现更为复杂的鉴权策略,比如:
<authz:authorize ifAllGranted="ROLE_ADMIN"
ifAnyGranted="ROLE_USER"
ifNotGranted="ROLE_OTHER">
<h1>Hello, World!</h1>
</authz:authorize>
下面我们来看看显示鉴权信息的标签用法:
Welcome <authz:authentication operation="username"/>
我们通过这个标签,把登录用户的用户名显示在页面上。
小结
在这一章,您初步学习了如何使用Spring Security为您的项目添加认证及授权的能力。在这一章中,我们介绍了写在配置文件中的用户认证源,使用了自动生成的登录页面,可说是学习了非常初步的使用方法。在下一章中,我们将进一步学习Spring Security的使用方法。
标签: spring secutiry 安全 java 系列 教学 web 开发
随便看看 |
最新文章 |
| ^返回页首 |