`
jiangwubo
  • 浏览: 25348 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多
 
Spring Security
参考文档
Ben Alex, Luke Taylor
2.0.x
________________________________________
序言
I. 入门
1. 介绍
1.1. Spring Security是什么?
1.2. 历史
1.3. 发行版本号
1.4. 获得源代码
2. Security命名空间配置
2.1. 介绍
2.1.1. 命名空间的设计
2.2. 开始使用安全命名空间配置
2.2.1. 配置web.xml
2.2.2. 最小 <http>配置
2.2.2.1. auto-config包含了什么?
2.2.2.2. 表单和基本登录选项
2.2.3. 使用其他认证提供器
2.2.3.1. 添加一个密码编码器
2.3. 高级web特性
2.3.1. Remember-Me认证
2.3.2. 添加HTTP/HTTPS信道安全
2.3.3. 同步Session控制
2.3.4. OpenID登录
2.3.5. 添加你自己的filter
2.3.5.1. 设置自定义 AuthenticationEntryPoint
2.3.6. 防止Session固定攻击
2.4. 保护方法
2.4.1. <global-method-security>元素
2.4.1.1. 使用protect-pointcut添加安全切点
2.4.2. intercept-methods Bean 渲染器
2.5. 默认的AccessDecisionManager
2.5.1. 自定义AccessDecisionManager
2.6. 默认验证管理器
3. 示例程序
3.1. Tutorial示例
3.2. Contacts
3.3. LDAP例子
3.4. CAS例子
3.5. Pre-Authentication例子
4. Spring Security社区
4.1. 任务跟踪
4.2. 成为参与者
4.3. 更多信息
II. 总体结构
5. 技术概述
5.1. 运行环境
5.2. 共享组件
5.2.1. SecurityContextHolder, SecurityContext 和 Authentication对象
5.2.2. UserDetailsService
5.2.3. GrantedAuthority
5.2.4. 小结
5.3. 验证
5.3.1. ExceptionTranslationFilter
5.3.2. AuthenticationEntryPoint
5.3.3. AuthenticationProvider
5.3.4. 直接设置SecurityContextHolder的内容
5.4. 安全对象
5.4.1. 安全和AOP建议
5.4.2. AbstractSecurityInterceptor
5.4.2.1. 配置属性是什么?
5.4.2.2. RunAsManager
5.4.2.3. AfterInvocationManager
5.4.2.4. 扩展安全对象模型
6. 支持的基础设施
6.1. 国际化
6.2. 过滤器
6.3. 标签库
6.3.1. 配置
6.3.2. 使用
7. 信道安全
7.1. 总述
7.2. 配置
7.3. 总结
III. 认证
8. 通用认证服务
8.1. 机制,供应者和入口
8.2. UserDetails 和相关类型
8.2.1. 内存里认证
8.2.2. JDBC认证
8.2.2.1. 默认用户数据库表结构
8.3. 并行会话处理
8.4. 认证标签库
9. DAO认证提供器
9.1. 综述
9.2. 配置
10. LDAP认证
10.1. 综述
10.2. 在Spring Security里使用LDAP
10.3. 配置LDAP服务器
10.3.1. 使用嵌入测试服务器
10.3.2. 使用绑定认证
10.3.3. 读取授权
10.4. 实现类
10.4.1. LdapAuthenticator实现
10.4.1.1. 常用功能
10.4.1.2. BindAuthenticator
10.4.1.3. PasswordComparisonAuthenticator
10.4.1.4. 活动目录认证
10.4.2. 链接到LDAP服务器
10.4.3. LDAP搜索对象
10.4.3.1. FilterBasedLdapUserSearch
10.4.4. LdapAuthoritiesPopulator
10.4.5. Spring Bean配置
10.4.6. LDAP属性和自定义UserDetails
11. 表单认证机制
11.1. 概述
11.2. 配置
12. 基本认证机制
12.1. 概述
12.2. 配置
13. 摘要式认证
13.1. 概述
13.2. 配置
14. Remember-Me认证
14.1. 概述
14.2. 简单基于散列标记的方法
14.3. 持久化标记方法
14.4. Remember-Me接口和实现
14.4.1. TokenBasedRememberMeServices
14.4.2. PersistentTokenBasedRememberMeServices
15. Java认证和授权服务(JAAS)供应器
15.1. 概述
15.2. 配置
15.2.1. JAAS CallbackHandler
15.2.2. JAAS AuthorityGranter
16. 预认证场景
16.1. 预认证框架类
16.1.1. AbstractPreAuthenticatedProcessingFilter
16.1.2. AbstractPreAuthenticatedAuthenticationDetailsSource
16.1.2.1. J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
16.1.3. PreAuthenticatedAuthenticationProvider
16.1.4. PreAuthenticatedProcessingFilterEntryPoint
16.2. 具体实现
16.2.1. 请求头认证(Siteminder)
16.2.1.1. Siteminder示例配置
16.2.2. J2EE容器认证
17. 匿名认证
17.1. 概述
17.2. 配置
18. X.509认证
18.1. 概述
18.2. 把X.509认证添加到你的web系统中
18.3. 为tomcat配置SSL
19. CAS认证
19.1. 概述
19.2. CAS是如何工作的
19.3. 配置CAS客户端
20. 替换验证身份
20.1. 概述
20.2. 配置
IV. 授权
21. 通用授权概念
21.1. 授权
21.2. 处理预调用
21.2.1. AccessDecisionManager
21.2.1.1. 基于投票的AccessDecisionManager实现
21.3. 处理后决定
21.3.1. ACL提醒后决议提供器
21.3.2. ACL-Aware AfterInvocationProviders (老 ACL 模块)
21.4. 授权标签库
22. 安全对象实现
22.1. AOP联盟 (MethodInvocation) 安全拦截器
22.1.1. 精确的 MethodSecurityIterceptor 配置
22.2. AspectJ (JoinPoint) 安全拦截器
22.3. FilterInvocation 安全拦截器
23. 领域对象安全(ACLs)
23.1. 概述
23.2. 关键概念
23.3. 开始
24. acegi到spring security的转换方式
24.1. Spring Security是什么
24.2. 目标
24.3. 步骤
24.4. 总结
A. 安全数据库表结构
A.1. User表
A.1.1. 组权限
A.2. 持久登陆(Remember-Me)表
A.3. ACL表
A.3.1. Hypersonic SQL
A.3.1.1. PostgreSQL
B. 安全命名空间
B.1. Web应用安全 - <http>元素
B.1.1. <http>属性
B.1.1.1. servlet-api-provision
B.1.1.2. path-type
B.1.1.3. lowercase-comparisons
B.1.1.4. session-fixation-protection
B.1.1.5. realm
B.1.1.6. entry-point-ref
B.1.1.7. access-decision-manager-ref
B.1.1.8. access-denied-page
B.1.1.9. once-per-request
B.1.1.10. create-session
B.1.2. <intercept-url>元素
B.1.2.1. pattern
B.1.2.2. method
B.1.2.3. access
B.1.2.4. requires-channel
B.1.3. <port-mappings>元素
B.1.4. <form-login>元素
B.1.4.1. login-page
B.1.4.2. login-processing-url
B.1.4.3. default-target-url
B.1.4.4. always-use-default-target
B.1.4.5. authentication-failure-url
B.1.5. <http-basic>元素
B.1.6. <remember-me>元素
B.1.6.1. data-source-ref
B.1.6.2. token-repository-ref
B.1.6.3. services-ref
B.1.6.4. token-repository-ref
B.1.6.5. key属性
B.1.6.6. token-validity-seconds
B.1.6.7. user-service-ref
B.1.7. <concurrent-session-control>元素
B.1.7.1. max-sessions属性
B.1.7.2. expired-url属性
B.1.7.3. exception-if-maximum-exceeded属性
B.1.7.4. session-registry-alias和session-registry-ref属性
B.1.8. <anonymous>元素
B.1.9. <x509>元素
B.1.9.1. subject-principal-regex属性
B.1.9.2. user-service-ref属性
B.1.10. <openid-login>元素
B.1.11. <logout>元素
B.1.11.1. logout-url属性
B.1.11.2. logout-success-url属性
B.1.11.3. invalidate-session属性
B.2. 认证服务
B.2.1. <authentication-provider>元素
B.2.2. 使用<custom-authentication-provider>注册一个AuthenticationProvider
B.2.3. <authentication-manager>元素
B.3. 方法安全
B.3.1. <global-method-security>元素
B.3.1.1. <secured-annotations>和<jsr250-annotations>属性
B.3.1.2. 安全方法使用<protect-pointcut>
B.3.1.3. <custom-after-invocation-provider>元素
B.3.2. LDAP命名空间选项
B.3.2.1. 使用<ldap-server>元素定义LDAP服务器
B.3.2.2. <ldap-provider>元素
B.3.2.3. <ldap-user-service>元素
序言
Spring Security为基于J2EE的企业应用软件提供了一套全面的安全解决方案。正如你在本手册中看到的那样,我们尝试为您提供一套好用,高可配置的安全系统。
安全问题是一个不断变化的目标,更重要的是寻求一种全面的,系统化的解决方案。 在安全领域我们建议你采取“分层安全”,这样让每一层确保本身尽可能的安全,并为其他层提供额外的安全保障。 每层自身越是“紧密”,你的程序就会越鲁棒越安全。 在底层,你需要处理传输安全和系统认证,减少“中间人攻击”(man-in-the-middle attacks)。 接下来,我们通常会使用防火墙,结合VPN或IP安全来确保只有获得授权的系统才能尝试连接。 在企业环境中,你可能会部署一个DMZ(demilitarized zone,隔离区),将面向公众的服务器与后端数据库,应用服务器隔离开。 在以非授权用户运行进程和文件系统安全最大化上,你的操作系统也将扮演一个关键的角色。 操作系统通常配置了自己的防火墙。 然后你要防止针对系统的拒绝服务和暴力攻击。 入侵检测系统在检测和应对攻击的时候尤其有用。这些系统可以实时屏蔽恶意TCP/IP地址。 在更高层上,你需要配置Java虚拟机,将授予不同java类型权限最小化,然后,你的应用程序要添加针对自身特定问题域的安全配。Spring Security使后者 - 应用程序安全变得更容易。
当然,你需要妥善处理上面提到的每个安全层,以及包含于每个层的管理因素。 这些管理因素具体包括:安全公告检测,补丁,人工诊断,审计,变更管理,工程管理系统,数据备份,灾难回复,性能评测,负载检测,集中日志,应急反应程序等等。
Spring Security关注的重点是在企业应用安全层为您提供服务,你将发现业务问题领域存在着各式各样的需求。银行系统跟电子商务应用就有很大的不同。电子商务系统与企业销售自动化工具又有很大不同。这些客户化需求让应用安全显得有趣,富有挑战性而且物有所值。
请阅读Part I, “入门”部分,以它作为开始。它向你介绍了整个框架和以命名空间为基础系统配置方式,让你可以很快启动并运行系统。要是想更多的了解Spring Security是如何工作和一些你可能需要用到的类,你应该阅读Part II, “总体结构”部分。本指南的其余部分使用了较传统的参考文档方式,请按照自己的需要选择阅读的部分。 我们也推荐你阅读尽可能多的在应用安全中可能出现的一般问题。 Spring Security也不是万能的,它不可能解决所有问题。 重要的一点,应用程序应该从一开始就为安全做好设计。 企图改造它也不是一个好主意。 特别的,如果你在制作一个web应用,你应该知道许多潜在的脆弱性,比如跨域脚本,伪造请求和会话劫持,这些都是你在一开始就应该考虑到的。 OWASP网站(http://www.owasp.org/)维护了一个web应用脆弱性前十名的名单,还有很多有用的参考信息。
我们希望你觉得这是一篇很有用的参考指南,并欢迎您提供反馈意见和建议。
最后,欢迎加入Spring Security 社区。
Part I. 入门
本 指南的后面部分提供对框架结构和实现类的深入讨论,了解它们,对你进行复杂的定制是十分重要的。在这部分,我们将介绍Spring Security 2.0,简要介绍该项目的历史,然后看看如何开始在程序中使用框架。特别是,我们将看看命名控件配置提供了一个更加简单的方式,在使用传统的spring bean配置时,你不得不实现所有类。
我们也会看看可用的范例程序。它们值得试着运行,实验,在你阅读后面的章节之前 - 你可以在对框架有了更多连接之后再回来看这些例子。
Chapter 1. 介绍
1.1. Spring Security是什么?
Spring Security为基于J2EE企业应用软件提供了全面安全服务。 特别是使用领先的J2EE解决方案-spring框架开发的企业软件项目。 如果你没有使用Spring开发企业软件,我们热情的推荐你仔细研究一下。 熟悉Spring-尤其是依赖注入原理-将帮助你更快的掌握Spring Security。
人 们使用Spring Security有很多种原因,不过通常吸引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。提到这些规范,特别要指出的是它们不能在WAR或EAR级别进行移植。这样,如果你 更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用系统进行重新配置安全。使用Spring Security解决了这些问题,也为你提供了很多有用的,完全可定制的其他安全特性。
你可能知道,安全包括两个主要操作。 第一个被称为“认证”,是为用户建立一个他所声明的主体。 主体一般是指用户,设备或可以在你系统中执行行动的其他系统。 “授权”指的一个用户能否在你的应用中执行某个操作。 在到达授权判断之前,身份的主体已经由身份验证过程建立了。 这些概念是通用的,不是Spring Security特有的。
在身份验证层面,Spring Security广泛支持各种身份验证模式。 这些验证模型绝大多数都由第三方提供,或正在开发的有关标准机构提供的,例如Internet Engineering Task Force。 作为补充,Spring Security也提供了自己的一套验证功能。 Spring Security目前支持认证一体化和如下认证技术:
• HTTP BASIC authentication headers (一个基于IEFT RFC的标准)
• HTTP Digest authentication headers (一个基于IEFT RFC的标准)
• HTTP X.509 client certificate exchange (一个基于IEFT RFC的标准)
• LDAP (一个非常常见的跨平台认证需要做法,特别是在大环境)
• Form-based authentication (提供简单用户接口的需求)
• OpenID authentication
• Computer Associates Siteminder
• JA-SIG Central Authentication Service (也被称为CAS,这是一个流行的开源单点登录系统)
• Transparent authentication context propagation for Remote Method Invocation (RMI) and HttpInvoker (一个Spring远程调用协议)
• Automatic "remember-me" authentication (这样你可以设置一段时间,避免在一段时间内还需要重新验证)
• Anonymous authentication (允许任何调用,自动假设一个特定的安全主体)
• Run-as authentication (这在一个会话内使用不同安全身份的时候是非常有用的)
• Java Authentication and Authorization Service (JAAS)
• Container integration with JBoss, Jetty, Resin and Tomcat (这样,你可以继续使用容器管理认证,如果想的话)
• Java Open Source Single Sign On (JOSSO) *
• OpenNMS Network Management Platform *
• AppFuse *
• AndroMDA *
• Mule ESB *
• Direct Web Request (DWR) *
• Grails *
• Tapestry *
• JTrac *
• Jasypt *
• Roller *
• Elastic Plath *
• Atlassian Crowd *
• 你自己的认证系统(向下看)
(* 是指由第三方提供,查看我们的整合网页,获得最新详情的链接。)
许多独立软件供应商(ISVs, independent software vendors)采用Spring Security,是因为它拥有丰富灵活的验证模型。 这样,无论终端用户需要什么,他们都可以快速集成到系统中,不用花很多功夫,也不用让用户改变运行环境。 如果上述的验证机制都没有满足你的需要,Spring Security是一个开放的平台,编写自己的验证机制是十分简单的。 Spring Security的许多企业用户需要整合不遵循任何特定安全标准的“遗留”系统,Spring Security在这类系统上也表现的很好。
有时基本的认证是不够的。 有时你需要根据在主体和应用交互的方式来应用不同的安全措施。 比如,你可能,为了保护密码,不被jie ting或受到中间人攻击,希望确保请求只通过HTTPS到达。 或者,你希望确保发起请求的是一个真正的人,而不是机器人或其他自动化程序。 这对保护找回密码不被暴力攻击特别有帮助,或者让别人更难复制你程序中的关键内容。 为了帮助你实现这些目标,Spring Security支持自动“通道安全”,整合jcaptcha一体化进行人类用户检测。
Spring Security不仅提供认证功能,也提供了完备的授权功能。 在授权方面主要有三个领域,授权web请求,授权被调用方法,授权访问单个对象的实例。 为了帮你了解它们之间的区别,对照考虑授在Servlet规范web模式安全,EJB容器管理安全,和文件系统安全方面的授权方式。 Spring Security在所有这些重要领域都提供了完备的能力,我们将在这份参考指南的后面进行探讨。
1.2. 历史
Spring Security开始于2003年年底,那时候叫“spring的acegi安全系统”。 起因是Spring开发者邮件列表中的一个问题,有人提问是否考虑提供一个基于spring的安全实现。 在当时Spring的社区相对较小(尤其是和今天的规模比!),其实Spring本身是从2003年初才作为一个sourceforge的项目出现的。 对这个问题的回应是,这的确是一个值得研究的领域,虽然限于时间问题阻碍了对它的继续研究。
有鉴于此,一个简单的安全实现建立起来了,但没有发布。 几周之后,spring社区的其他成员询问安全问题,代码就被提供给了他们。 随后又有人请求,在2004年一月左右,有20人在使用这些代码。 另外一些人加入到这些先行者中来,并建议在sourceforge上建立一个项目,项目在2004年3月正式建立起来。
在早期,项目本身没有自己的认证模块。 认证过程都是依赖容器管理安全的,而acegi则注重授权。 这在一开始是合适的,但随着越来越多用户要求提供额外的容器支持,基于容器认证的限制就显现出来了。 还有一个有关的问题,向容器的classpath中添加新jar,常常让最终用户感到困惑,又容易出现配置错误。
随后acegi加入了认证服务。大约一年后,acegi成为spring的官方子项目。 经过了两年半在许多生产软件项目中的活跃使用和数以万计的改善和社区的贡献,1.0.0最终版本发布于2006年5月。
acegi在2007年年底,正式成为spring组合项目,被更名为“Spring Security”。
现在,Spring Security成为了一个强大而又活跃的开源社区。 在Spring Security支持论坛上有成千上万的信息。 有一个积极的核心开发团队专职开发,一个积极的社区定期共享补丁并支持他们的同伴。
1.3. 发行版本号
了解spring Security发行版本号是非常有用的。它可以帮助你判断升级到新的版本是否需要花费很大的精力。 我们使用apache便携式运行项目版本指南,可以在以下网址查看http://apr.apache.org/versioning.html。 为了方便大家,我们引用页面上的一段介绍:
“版本号是一个包含三个整数的组合:主要版本号.次要版本号.补丁。 基本思路是主要版本是不兼容的,大规模升级API。 次要版本号在源代码和二进制要与老版本保持兼容,补丁则意味着向前向后的完全兼容。”
1.4. 获得源代码
Spring Security是一个开源项目,我们大力推荐你从subversion获得源代码。 这样你可以获得所有的示例,你可以很容易的建立目前最新的项目。 获得项目的源代码对调试也有很大的帮助。 异常堆栈不再是模糊的黑盒问题,你可以直接找到发生问题的那一行,查找发生了什么额外难题。 源代码也是项目的最终文档,常常是最简单的方法,找出这些事情是如何工作的。
要像获得项目最新的源代码,使用如下subversion命令:
    svn checkout http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/trunk/
你可以获得特定版本的源代码 http://acegisecurity.svn.sourceforge.net/svnroot/acegisecurity/spring-security/tags/.
Security命名空间配置
2.1. 介绍
从Spring-2.0开始可以使用命名空间的配置方式。 使用它呢,可以通过附加xml架构,为传统的spring beans应用环境语法做补充。 你可以在spring参考文档得到更多信息。 命名空间元素可以简单的配置单个bean,或使用更强大的,定义一个备用配置语法,这可以更加紧密的匹配问题域,隐藏用户背后的复杂性。 简单元素可能隐藏事实,多种bean和处理步骤添加到应用环境中。 比如,把下面的security命名元素添加到应用环境中,将会为测试用途,在应用内部启动一个内嵌LDAP服务器:
  <security:ldap-server />
这比配置一个Apache目录服务器bean要简单得多。 最常见的替代配置需求都可以使用ldap-server元素的属性进行配置,这样用户就不用担心他们需要设置什么,不用担心bean里的各种属性。 [1]。使用一个良好的XML编辑器来编辑应用环境文件,应该提供可用的属性和元素信息。 我们推荐你尝试一下 SpringSource工具套件 因为它具有处理spring组合命名空间的特殊功能。
要开始在你的应用环境里使用security命名空间,你所需要的就是把架构声明添加到你的应用环境文件里:
 
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:security="http://www.springframework.org/schema/security"
  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-3.0.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    ...
</beans>
 
在许多例子里,你会看到(在示例中)应用,我们通常使用"security"作为默认的命名空间,而不是"beans",这意味着我们可以省略所有security命名空间元素的前缀,使上下文更容易阅读。 如果你把应用上下文分割成单独的文件,让你的安全配置都放到其中一个文件里,这样更容易使用这种配置方法。 你的安全应用上下文应该像这样开头
<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-3.0.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    ...
</beans:beans>
就在这一章里,我们都将假设使用这种语法。
2.1.1. 命名空间的设计
命名空间被用来设计成,处理框架内最常见的功能,提供一个简化和简洁的语法,使他们在一个应用程序里。 这种设计是基于框架内的大型依赖,可以分割成下面这些部分:
• Web/HTTP安全 - 最复杂的部分。设置过滤器和相关的服务bean来应用框架验证机制, 保护URL,渲染登录和错误页面还有更多。
• 业务类(方法)安全 - 可选的安全服务层。
• AuthenticationManager - 通过框架的其它部分,处理认证请求。一个默认的实例会通过命名空间注册到内部。
• AccessDecisionManager - 提供访问的决定,适用于web以及方法的安全。一个默认的主体会被注册,但是你也可以选择自定义一个,使用正常的spring bean语法进行声明。
• AuthenticationProviders - 验证管理器验证用户的机制。 该命名空间提供几种标准选项,意味着使用传统语法添加自定义bean。
• UserDetailsService - 密切相关的认证供应器,但往往也需要由其他bean需要。
下一章中,我们将看到如何把这些放到一起工作。
2.2. 开始使用安全命名空间配置
在本节中,我们来看看如何使用一些框架里的主要配置,建立一个命名空间配置。 我们假设你最初想要尽快的启动运行,为已有的web应用添加认证支持和权限控制,使用一些测试登录。 然后我们看一下如何修改一下,使用数据库或其他安全信息残酷。 在以后的章节里我们将引入更多高级的命名空间配置选项。
2.2.1. 配置web.xml
我们要做的第一件事是把下面的filter声明添加到 web.xml 文件中:
       
<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的web机制提供了一个调用钩子。 DelegatingFilterProxy是一个Spring Framework的类,它可以代理一个application context中定义的Spring bean所实现的filter。 这种情况下,bean的名字是"springSecurityFilterChain",这是由命名空间创建的用于处理web安全的一个内部的机制。 注意,你不应该自己使用这个bean的名字。 一旦你把这个添加到你的web.xml中,你就准备好开始编辑呢的application context文件了。 web安全服务是使用<http>元素配置的。
2.2.2. 最小 <http>配置
只需要进行如下配置就可以实现安全配置:
  <http auto-config='true'>
    <intercept-url pattern="/**" access="ROLE_USER" />
  </http>
 
这表示,我们要保护应用程序中的所有URL,只有拥有 ROLE_USER角色的用户才能访问。
Note
你可以使用多个<intercept-url>元素为不同URL的集合定义不同的访问需求,它们会被归入一个有序队列中,每次取出最先匹配的一个元素使用。 所以你必须把期望使用的匹配条件放到最上边。
要是想添加一些用户,你可以直接使用下面的命名空间直接定义一些测试数据:
  <authentication-provider>
    <user-service>
      <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
      <user name="bob" password="bobspassword" authorities="ROLE_USER" />
    </user-service>
  </authentication-provider>
 
       
如果你熟悉以前的版本,你很可能已经猜到了这里是怎么回事。 <http>元素会创建一个FilterChainProxy和filter使用的bean。 以前常常出现的,因为filter顺序不正确产生的问题,不会再出现了,现在这些过滤器的位置都是预定义好的。
<authentication-provider>元素创建了一个DaoAuthenticationProvider bean,<user-service>元素创建了一个InMemoryDaoImpl。 一个ProviderManager bean通常是由命名空间过程系统创建的, DaoAuthenticationProvider自动注册到它上面。 你可以在命名空间附录中找到关于创建这个bean的更新信息。
上面的配置定义了两个用户,他们在应用程序中的密码和角色(用在权限控制上)。 也可以从一个标准properties文件中读取这些信息,使用user-service的properties属性。 参考in-memory authentication获得更多信息。 使用<authentication-provider>元素意味着用户信息将被认证管理用作处理认证请求。
现在,你可以启动程序,然后就会进入登录流程了。 试试这个,或者试试工程里的"tutorial"例子。 上述配置实际上把很多服务添加到了程序里,因为我们使用了auto-config属性。 比如,表单登录和"remember-me"服务自动启动了。
2.2.2.1. auto-config包含了什么?
我们在上面用到的auto-config属性,其实是下面这些配置的缩写:
  <http>
    <form-login />
    <http-basic />
    <logout />
  </http>
 
         
这些元素分别与form-login,基本认证和注销处理对应。 [2] 他们拥有各自的属性,来改变他们的具体行为。
2.2.2.2. 表单和基本登录选项
你也许想知道,在需要登录的时候,去哪里找这个登录页面,到现在为止我们都没有提到任何的HTML或JSP文件。 实际上,如果我们没有确切的指定一个页面用来登录,Spring Security会自动生成一个,基于可用的功能,为这个URL使用标准的数据,处理提交的登录,然后发送到默认的目标URL。 然而,命名空间提供了许多支持,让你可以自定义这些选项。 比如,如果你想实现自己的登录页面,你可以使用:
  <http auto-config='true'>
    <intercept-url pattern="/login.jsp*" filters="none"/>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <form-login login-page='/login.jsp'/>
  </http>
 
       
注意,你依旧可以使用auto-config。 这个form-login元素会覆盖默认的设置。 也要注意我们需要添加额外的intercept-url元素,指定用来做登录的页面的URL,这些URL不应该被安全filter处理。 否则,这些请求会被/**部分拦截,它没法访问到登录页面。 如果你想使用基本认证而不是表单登录,可以把配置修改成如下所示:
  <http auto-config='true'>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <http-basic />
  </http>
 
       
基本身份认证会被优先用到,在用户尝试访问一个受保护的资源时,用来提示用户登录。 在这种配置中,表单登录依然是可用的,如果你还想用的话,比如,把一个登录表单内嵌到其他页面里。
2.2.2.2.1. 设置一个默认的提交登陆目标
如果在进行表单登陆之前,没有试图去访问一个被保护的资源,default-target-url就会起作用。 这是用户登陆后会跳转到的URL,默认是"/"。 你也可以把always-use-default-target属性配置成"true",这样用户就会一直跳转到这一页(无论登陆是“跳转过来的”还是用户特定进行登陆)。 如果你的系统一直需要用户从首页进入,就可以使用它了,比如:
  <http>
    <intercept-url pattern='/login.htm*' filters='none'/>
    <intercept-url pattern='/**' access='ROLE_USER' />
    <form-login login-page='/login.htm' default-target-url='/home.htm' always-use-default-target='true' />
  </http>
 
           
2.2.3. 使用其他认证提供器
现实中,你会需要更大型的用户信息源,而不是写在application context里的几个名字。 多数情况下,你会想把用户信息保存到数据库或者是LDAP服务器里。 LDAP命名空间会在LDAP章里详细讨论,所以我们这里不会讲它。 如果你自定义了一个Spring Security的UserDetailsService实现,在你的application context中名叫"myUserDetailsService",然后你可以使用下面的验证。
  <authentication-provider user-service-ref='myUserDetailsService'/>
 
       
如果你想用数据库,可以使用下面的方式
  <authentication-provider>
    <jdbc-user-service data-source-ref="securityDataSource"/>
  </authentication-provider>
 
       
这里的"securityDataSource"就是 DataSource bean在application context里的名字,它指向了包含着Spring Security用户信息的表。 另外,你可以配置一个Spring Security JdbcDaoImpl bean,使用user-service-ref属性指定:
  <authentication-provider user-service-ref='myUserDetailsService'/>

  <beans:bean id="myUserDetailsService" class="org.springframework.security.userdetails.jdbc.JdbcDaoImpl">
    <beans:property name="dataSource" ref="dataSource"/>
  </beans:bean>
 
       
你也可以通过在bean定义中添加<custom-authentication-provider>元素来使用标准AuthenticationProvider bean。 查看Section 2.6, “默认验证管理器”了解更多信息。
2.2.3.1. 添加一个密码编码器
你的密码数据通常要使用一种散列算法进行编码。 使用<password-encoder>元素支持这个功能。 使用SHA加密密码,原始的认证供应器配置,看起来就像这样:
<authentication-provider>
  <password-encoder hash="sha"/>
  <user-service>
    <user name="jimi" password="d7e6351eaa13189a5a3641bab846c8e8c69ba39f" authorities="ROLE_USER, ROLE_ADMIN" />
    <user name="bob" password="4e7421b1b8765d8f9406d87e7cc6aa784c4ab97f" authorities="ROLE_USER" />
  </user-service>
</authentication-provider>
 
         
在使用散列密码时,用盐值防止字典攻击是个好主意,Spring Security也支持这个功能。 理想情况下,你可能想为每个用户随机生成一个盐值,不过,你可以使用从UserDetailsService读取出来的UserDetails对象中的属性。 比如,使用username属性,你可以这样用:
<password-encoder hash="sha">
  <salt-source user-property="username"/>
</password-encoder>
   
你可以通过password-encoder的ref属性,指定一个自定义的密码编码器bean。 这应该包含application context中一个bean的名字,它应该是Spring Security的PasswordEncoder接口的一个实例。
2.3. 高级web特性
2.3.1. Remember-Me认证
参考Remember-Me章获得remember-me命名空间配置的详细信息。
2.3.2. 添加HTTP/HTTPS信道安全
如果你的同时支持HTTP和HTTPS协议,然后你要求特定的URL只能使用HTTPS,这时可以直接使用<intercept-url>的requires-channel属性:
  <http>
    <intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/>
    <intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/>
    ...
  </http>
       
使用了这个配置以后,如果用户通过HTTP尝试访问"/secure/**"匹配的网址,他们会先被重定向到HTTPS网址下。 可用的选项有"http", "https" 或 "any"。 使用"any"意味着使用HTTP或HTTPS都可以。
如果你的程序使用的不是HTTP或HTTPS的标准端口,你可以用下面的方式指定端口对应关系:
         
  <http>
    ...
    <port-mappings>
      <port-mapping http="9080" https="9443"/>
    </port-mappings>
  </http>
       
你可以在Chapter 7, 信道安全找到更详细的讨论。
2.3.3. 同步Session控制
如果你希望限制单个用户只能登录到你的程序一次,Spring Security通过添加下面简单的部分支持这个功能。 首先,你需要把下面的监听器添加到你的web.xml文件里,让Spring Security获得session生存周期事件:
         
<listener>
  <listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
然后,在你的application context加入如下部分:
  <http>
    ...
    <concurrent-session-control max-sessions="1" />
  </http>
       
这将防止一个用户重复登录好几次-第二次登录会让第一次登录失效。 通常我们更想防止第二次登录,这时候我们可以使用
  <http>
    ...
    <concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true"/>
  </http>
       
第二次登录将被阻止。
2.3.4. OpenID登录
命名空间支持OpenID登录,替代普通的表单登录,或作为一种附加功能,只需要进行简单的修改:
  <http>
    <intercept-url pattern="/**" access="ROLE_USER" />
    <openid-login />
  </http>
 
你应该注册一个OpenID供应器(比如myopenid.com),然后把用户信息添加到你的内存<user-service>中:
  <user name="http://jimi.hendrix.myopenid.com/" password="notused" authorities="ROLE_USER" />
 
你应该可以使用myopenid.com网站登录来进行验证了。
2.3.5. 添加你自己的filter
如果你以前使用过Spring Security,你就应该知道这个框架里维护了一个过滤器链,来提供服务。 你也许想把你自己的过滤器添加到链条的特定位置,或者使用一个Spring Security的过滤器,这个过滤器现在还没有在命名空间配置中进行支持(比如CAS)。 或者你想要使用一个特定版本的标准命名空间过滤器,比如<form-login>创建的AuthenticationProcessingFilter,从而获得一些额外的配置选项的优势,这些可以通过直接配置bean获得。 你如何在命名空间配置里实现这些功能呢?过滤器链现在已经不能直接看到了。
过滤器顺序在使用命名空间的时候是被严格执行的。 每个Spring Security过滤器都实现了Spring的Ordered接口,这些通过命名空间穿件的过滤器在初始化的时候就预先被排好序了。 标准的过滤器在命名空间里都有自己的假名,有关创建过滤器的过滤器,假名和命名空间元素,属性可以在Table 2.1, “标准过滤器假名和顺序”中找到。
Table 2.1. 标准过滤器假名和顺序
假名 过滤器累 命名空间元素或属性
CHANNEL_FILTER ChannelProcessingFilter http/intercept-url
CONCURRENT_SESSION_FILTER ConcurrentSessionFilter http/concurrent-session-control
SESSION_CONTEXT_INTEGRATION_FILTER HttpSessionContextIntegrationFilter http
LOGOUT_FILTER LogoutFilter http/logout
X509_FILTER X509PreAuthenticatedProcessigFilter http/x509
PRE_AUTH_FILTER AstractPreAuthenticatedProcessingFilter Subclasses N/A
CAS_PROCESSING_FILTER CasProcessingFilter N/A
AUTHENTICATION_PROCESSING_FILTER AuthenticationProcessingFilter http/form-login
BASIC_PROCESSING_FILTER BasicProcessingFilter http/http-basic
SERVLET_API_SUPPORT_FILTER SecurityContextHolderAwareRequestFilter http/@servlet-api-provision
REMEMBER_ME_FILTER RememberMeProcessingFilter http/remember-me
ANONYMOUS_FILTER AnonymousProcessingFilter http/anonymous
EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter http
NTLM_FILTER NtlmProcessingFilter N/A
FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor http
SWITCH_USER_FILTER SwitchUserProcessingFilter N/A

你可以把你自己的过滤器添加到队列中,使用custom-filter元素,使用这些名字中的一个,来指定你的过滤器应该出现的位置:
  <beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter">
    <custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
  </beans:bean>
 
你还可以使用after 或 before属性,如果你想把你的过滤器添加到队列中另一个过滤器的前面或后面。 可以分别在position属性使用"FIRST" 或 "LAST"来指定你想让你的过滤器出现在队列元素的前面或后面。
避免过滤器位置发生冲突
如果你插入了一个自定义的过滤器,而这个过滤器可能与命名空间自己创建的标准过滤器放在同一个位置上,这样首要的是你不要错误包含命名空间的版本信息。 避免使用auto-config属性,然后删除所有会创建你希望替换的过滤器的元素。
注意,你不能替换那些<http>元素自己使用而创建出的过滤器,比如HttpSessionContextIntegrationFilter, ExceptionTranslationFilter 或 FilterSecurityInterceptor。
如果你替换了一个命名空间的过滤器,而这个过滤器需要一个验证入口点(比如,认证过程是通过一个未通过验证的用户访问受保护资源的尝试来触发的),你将也需要添加一个自定义的入口点bean。
2.3.5.1. 设置自定义 AuthenticationEntryPoint
如果你没有通过命名空间,使用表单登陆,OpenID或基本认证,你可能想定义一个认证过滤器,并使用传统bean语法定义一个入口点然后把它链接到命名空间里,就像我们已经看到的那样。 对应的AuthenticationEntryPoint可以使用<http>元素中的entry-point-ref属性来进行设置。
CAS示例程序是一个在命名空间中使用自定义bean的好例子,包含这种语法。 如果你对认证入口点并不熟悉,可以在技术纵览章中找到关于它们的讨论。
2.3.6. 防止Session固定攻击
Session固定攻击是一个潜在危险,当一个恶意攻击者可以创建一个session访问一个网站的时候,然后说服另一个用户登录到同一个会话上(比如,发送给他们一个包含了session标识参数的链接)。 Spring Security通过在用户登录时,创建一个新session来防止这个问题。 如果你不需要保护,或者它与其他一些需求冲突,你可以通过使用<http>中的session-fixation-protection属性来配置它的行为,它有三个选项
• migrateSession - 创建一个新session,把原来session中所有属性复制到新session中。这是默认值。
• none - 什么也不做,继续使用原来的session。
• newSession - 创建一个新的“干净的”session,不会复制session中的数据。
2.4. 保护方法
Spring Security 2.0大幅改善了对你的服务层方法添加安全。 如果你使用Java 5或更高版本,还支持JSR-250的安全注解,这与框架提供的@secured注解相似。 你可以为单个bean提供安全控制,通过使用intercept-methods元素装饰bean声明,或者你可以使用AspectJ方式的切点来控制实体服务层里的多个bean。
2.4.1. <global-method-security>元素
这个元素用来在你的应用程序中启用基于安全的注解(通过在这个元素中设置响应的属性),也可以用来声明将要应用在你的实体application context中的安全切点组。 你应该只定义一个<global-method-security>元素。 下面的声明同时启用Spring Security的@Secured和JSR-250注解:
  <global-method-security secured-annotations="enabled" jsr250-annotations="enabled"/>
 
向一个方法(或一个类或一个接口)添加注解,会限制对这个方法的访问。 Spring Security原生注解支持为方法定义一系列属性。 这些属性将传递给AccessDecisionManager,进行决策。 这个例子来自tutorial sample,如果你想在程序中使用方法安全,那么它是一个很好的开始:
  public interface BankService {

    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public Account readAccount(Long id);

    @Secured("IS_AUTHENTICATED_ANONYMOUSLY")
    public Account[] findAccounts();

    @Secured("ROLE_TELLER")
    public Account post(Account account, double amount);
  }
2.4.1.1. 使用protect-pointcut添加安全切点
protect-pointcut是非常强大的,它让你可以用简单的声明对多个bean的进行安全声明。 参考下面的例子:
  <global-method-security>
    <protect-pointcut expression="execution(* com.mycompany.*Service.*(..))" access="ROLE_USER"/>
  </global-method-security>

         
这样会保护application context中的符合条件的bean的所有方法,这些bean要在com.mycompany包下,类名以"Service"结尾。 ROLE_USER的角色才能调用这些方法。 就像URL匹配一样,指定的匹配要放在切点队列的最前面,第一个匹配的表达式才会被用到。
2.4.2. intercept-methods Bean 渲染器
可选语法,让你可以指定安全,为一个特定的bean,使用元素在bean里。
<bean:bean id="target" class="com.mycompany.myapp.MyBean">
    <intercept-methods>
        <protect method="set*" access="ROLE_ADMIN" />
        <protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
        <protect method="doSomething" access="ROLE_USER" />
    </intercept-methods>
</bean:bean>
这让你配置安全属性,为单独的方法,在bean或简单通配符模式。
2.5. 默认的AccessDecisionManager
这章假设你有一些Spring Security权限控制有关的架构知识。 如果没有,你可以跳过这段,以后再来看,因为这章只是为了自定义的用户设置的,需要在简单基于角色安全的基础上加一些客户化的东西。
当你使用命名空间配置时,默认的AccessDecisionManager实例会自动注册,然后用来为方法调用和web URL访问做验证,这些都是基于你设置的intercept-url和protect-pointcut权限属性内容(和注解中的内容,如果你使用注解控制方法的权限)。
默认的策略是使用一个AffirmativeBased AccessDecisionManager ,以及RoleVoter 和AuthenticatedVoter。
2.5.1. 自定义AccessDecisionManager
如果你需要使用一个更复杂的访问控制策略,把它设置给方法和web安全是很简单的。
对于方法安全,你可以设置global-security里的access-decision-manager-ref属性,用对应 AccessDecisionManager bean在application context里的id:
  <global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
    ...
  </global-method-security>
 
web安全安全的语法也是一样,但是放在http元素里:
  <http access-decision-manager-ref="myAccessDecisionManagerBean">
    ...
  </http>
 
2.6. 默认验证管理器
我们大概知道命名空间配置会自动为我们注册一个验证管理器bean。 这是一个Spring Security的ProviderManager类,如果你以前使用过框架,应该对它很熟悉了。 如果你在命名空间中使用了HTTP或方法安全,你不能使用自定义的AuthenticationManager,但你已经可以对使用的AuthenticationProvider进行完全的控制了,所以这不会是一个问题。
你也许想为ProviderManager注册另外的AuthenticationProvider bean,你可以使用<custom-authentication-provider>元素实现。比如:
  <bean id="casAuthenticationProvider"
      class="org.springframework.security.providers.cas.CasAuthenticationProvider">
    <security:custom-authentication-provider />
    ...
  </bean>
 
另一个常见的需求是,上下文中的另一个bean可能需要引用AuthenticationManager。 这里有一个特殊的元素,可以让你为AuthenticationManager注册一个别名,然后你可以application context的其他地方使用这个名字。
  <security:authentication-manager alias="authenticationManager"/>

  <bean id="customizedFormLoginFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
     <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
     <property name="authenticationManager" ref="authenticationManager"/>
     ...
  </bean>
 

________________________________________
[1] 你可以在LDAP的章节里,找到更多有关使用的ldap-server的元素。


[2] 在3.0之前按,这里列表中还包含remember-me功能。 这是因为一些配置上容易冲突的问题所以在3.0中被移除了。 在3.0中,AnonymousProcessingFilter已经成为了默认的 <http>配置的一部分,所以<anonymous /> 元素无论是否设置auto-config都会被添加到配置中。
示例程序
项目中包含了很多web实例程序。 为了不让下载包变得太大,我们只把"tutorial"和"contacts"两个例子放到了zip发布包里。 你可以自己编译部署它们,也可以从Maven中央资源库里获得单独的war文件。 我们建议你使用前一种方法。 你可以按照简介里的介绍获得源代码,使用maven编译它们也很简单。 如果你需要的话,可以在 http://www.springsource.org/security/ 网站上找到更多信息。
3.1. Tutorial示例
这个tutorial示例是带你入门的很好的一个基础例子。 它完全使用了简单命名空间配置。 编译好的应用就放在zip发布包中,已经准备好发布到你的web容器中(spring-security-samples-tutorial-2.0.x.war)。 使用了form-based验证机制,与常用的remember-me验证提供器相结合,自动使用cookie记录登录信息。
我们推荐你从tutorial例子开始,因为XML非常小,也很容易看懂。 更重要的是,你很容易就可以把这个XML文件(和它对应的web.xml入口)添加到你的程序中。 只有做基本集成成功的时候,我们建议你试着添加方法验证和领域对象安全。
3.2. Contacts
Contacts例子,是一个很高级的例子,它在基本程序安全上附加了领域对象的访问控制列表,演示了更多强大的功能。
要发布它,先把Spring Security发布中的war文件按复制到你的容器的webapps目录下。 这个war文件应该叫做spring-security-samples-contacts-2.0.0.war(后边的版本号,很大程度上依赖于你使用的发布版本)。
在启动你的容器之后,检测一下程序是不是加载了,访问http://localhost:8080/contacts(或是其他你把war发布后,对应于你web容器的URL)。
下一步,点击"Debug"。 你将看到需要登录的提示,这页上会有一些测试用的用户名和密码。 随便使用其中的一个通过认证,就会看到结果页面。 它应该会包含下面这样的一段成功信息:

Security Debug Information

Authentication object is of type:
org.springframework.security.authentication.UsernamePasswordAuthenticationToken

Authentication object as a String:

org.springframework.security.authentication.UsernamePasswordAuthenticationToken@1f127853:
Principal: org.springframework.security.core.userdetails.User@b07ed00: Username: rod; \
Password: [PROTECTED]; Enabled: true; AccountNonExpired: true;
credentialsNonExpired: true; AccountNonLocked: true; \
Granted Authorities: ROLE_SUPERVISOR, ROLE_USER; \
Password: [PROTECTED]; Authenticated: true; \
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: \
RemoteIpAddress: 127.0.0.1; SessionId: 8fkp8t83ohar; \
Granted Authorities: ROLE_SUPERVISOR, ROLE_USER

Authentication object holds the following granted authorities:

ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR)
ROLE_USER (getAuthority(): ROLE_USER)

Success! Your web filters appear to be properly configured!
   
一旦你成功的看到了上面的信息,就可以返回例子程序的主页,点击"Manage"了。 然后你就可以尝试这个程序了。 注意,只有当前登录的用户对应的联系信息会显示出来,而且只有ROLE_SUPERVISOR权限的用户可以授权删除他们的联系信息。 在这场景后面,MethodSecurityInterceptor保护着业务对象。
陈程序允许你修改访问控制列表,分配不同的联系方式。 确保自己好好试用过,看看程序里的上下文XML文件,搞明白它是如何运行的。
3.3. LDAP例子
LDAP例子程序提供了一个基础配置,同时使用命名空间配置和使用传统方式bean的配置方式,这两种配置方式都写在application context文件里。 这意味着,在这个程序里,其实是配置了两个定义验证提供器。
3.4. CAS例子
CAS示例要求你同时运行CAS服务器和CAS客户端。 它没有包含在发布包里,你应该使用简介中的介绍来获得源代码。 你可以在sample/cas目录下找到对应的文件。 这里还有一个Readme.txt文件,解释如何从源代码树中直接运行服务器和客户端,提供完全的SSL支持。 你应该下载CAS服务器web程序(一个war文件)从CAS网站,把它放到samples/cas/server目录下。
3.5. Pre-Authentication例子
这个例子演示了如何从pre-authentication框架绑定bean,从J2EE容器中获得有用的登录信息。 用户名和角色是由容器设置的。
代码在samples/preauth目录下。
Spring Security社区
4.1. 任务跟踪
Spring Security使用JIRA管理bug报告和扩充请求。 如果你发现一个bug,请使用JIRA提交一个报告。 不要把它放到支持论坛上,邮件列表里,或者直接发邮件给项目开发者。 这样做法是特设的,我们更愿意使用更正式的方式管理bug。
如果有可能,最好为你的任务报告提供一个Junit单元测试,演示每一种不正确的行为。 或者,更好的是,提供一个不定来修正这个问题。 一般来说,扩充也也可以提交到任务跟踪系统里,虽然我们只接受提供了对应的单元测试的扩充请求。 因为保证项目的测试覆盖率是非常必要的,它需要适当的进行维护。
你可以访问任务跟踪的网址 http://jira.springframework.org/browse/SEC。
4.2. 成为参与者
我们欢迎你加入到Spring Security项目中来。 这里有很多贡献的方式,包括在论坛上阅读别人的帖子发表回复,写新代码,提升旧代码,帮助写文档,开发例子或指南,或简单的提供建议。
4.3. 更多信息
欢迎大家为Spring Security提出问题或评论。 你可以使用Spring社区论坛网址http://forum.springframework.org 同框架的其他用户讨论Spring Security。 记得使用JIRA提交bug,这部分在上面提到过了。 我们也欢迎大家加入Acegisecurity-developer邮件列表,特别是对设计部分的讨论。 交通量是非常轻的。
Part II. 总体结构
和大多数软件一样,Spring Security有一个一定的中央接口,类和抽象概念,贯穿整个框架。 在指南的这个部分,我们将介绍Spring Security,在解释这些中央元素之前,有必要进行成功的计划,执行Spring Security整合。
技术概述
5.1. 运行环境
Spring Security可以运行在标准的Java 1.4运行环境下。 它也支持Java 5.0,不过这部分代码单独打包起来,放到发布的, 文件名是"tiger"前缀的JAR文件里。 因为Spring Security的目标是自己容器内管理, 所以不需要为你的Java运行环境进行什么特别的配置。 特别是, 不需要特别配置一个Java Authentication and Authorization Service (JAAS)策略文件, 也不需要把Spring Security放到server的classLoader下。
这些设计确保了发布时的最大轻便性, 你可以简单把你的目标文件(JAR或WAR或EAR)从一个系统复制到另一个系统, 它会立即正常工作。
5.2. 共享组件
让我们展示一些Spring Security中很重要的共享组件。 被成为"shared"的组件,是指它在框架中占有很重要的位置, 框架离开它们就没法运行。 这些java类表达了维持系统的构建代码块, 所以理解他们的位置是非常重要的,即使你不需要直接跟他们打交道。
5.2.1. SecurityContextHolder, SecurityContext 和 Authentication对象
最基础的对象就是SecurityContextHolder。 我们把当前应用程序的当前安全环境的细节存储到它里边了, 它也包含了应用当前使用的主体细节。 默认情况下,SecurityContextHolder使用ThreadLocal存储这些信息, 这意味着,安全环境在同一个线程执行的方法一直是有效的, 即使这个安全环境没有作为一个方法参数传递到那些方法里。 这种情况下使用ThreadLocal是非常安全的, 只要记得在处理完当前主体的请求以后,把这个线程清除就行了。 当然,Spring Security自动帮你管理这一切了, 你就不用担心什么了。
有些程序并不适合使用ThreadLocal, 因为它们处理线程的特殊方法。比如,swing客户端也许希望 JVM里的所有线程都使用同一个安全环境。 为了这种情况,我们而已使用SecurityContextHolder.MODE_GLOBAL。 其他程序可能想让一个线程创建的线程也使用相同的安全主体。 这时可以使用 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL。 想要修改默认的SecurityContextHolder.MODE_THREADLOCAL模式,可以使用两种方法。 第一个是设置系统属性。另一个是调用 SecurityContextHolder的静态方法。大多数程序不需要修改默认值, 但是如果你需要做修改,先看一下 SecurityContextHolder的JavaDoc中的详细信息。
我们把安全主体和系统交互的信息都保存在 SecurityContextHolder中了。 Spring Security使用一个Authentication对应来表现这些信息。 虽然你通常不需要自己创建一个Authentication对象, 但是常见的情况是,用户查询 Authentication对象。你可以使用下面的代码 - 在你程序中的任何位置 - 来获得已认证用户的名字, 比如:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
  String username = ((UserDetails)principal).getUsername();
} else {
  String username = principal.toString();
}
上面的代码介绍了一定数量的,有趣的,几个关键对象之间的相互关系。 首先,你会注意到SecurityContextHolder 和 Authentication之间的中间对象。 这个SecurityContextHolder.getContext()方法会直接返回SecurityContext。
5.2.2. UserDetailsService
从上面的代码片段中还可以看出另一件事,就是你可以从Authentication对象中获得安全主体。 这个安全主体就是一个对象。 大多数情况下,可以强制转换成UserDetails对象。 UserDetails是一个Spring Security的核心接口。 它代表一个主体,是扩展的,而且是为特定程序服务的。 想一下UserDetails章节,在你自己的用户数据库和如何把Spring Security需要的数据放到SecurityContextHolder里。 为了让你自己的用户数据库起作用,我们常常把UserDetails转换成你系统提供的类,这样你就可以直接调用业务相关的方法了(比如getEmail(), getEmployeeNumber()等等)。
现在,你可能想知道,我应该什么时候提供这个UserDetails对象呢? 我怎么做呢? 我想你说这个东西是声明式的,我不需要写任何代码,怎么办? 简单的回答是, 这里有一个特殊的接口,叫UserDetailsService。 这个接口里的唯一一个方法, 接收String类型的用户名参数,返回UserDetails。 大多数验证提供器使用Spring Security代理UserDetailsService, 作为验证过程的一部分。 这个UserDetailsService用来建立Authentication对象, 保存在SecurityContextHolder里。 好消息是我们提供了好几个UserDetailsService实现, 其中一个使用内存里的map,另一个使用JDBC。 虽然,大多数用户倾向于写自己的, 使用这些实现常常放到已有的数据访问对象(DAO)上,表示它们的雇员,客户或其他企业应用中的用户。 记住这个优势,无论你用什么UserDetailsService返回的数据都可以通过SecurityContextHolder获得, 就像上面的代码片段讲的一样。
5.2.3. GrantedAuthority
除了主体,另一个Authentication提供的重要方法是getAuthorities()。 这个方法提供了GrantedAuthority对象数组。 毫无疑问,GrantedAuthority是赋予到主体的权限。 这些权限通常使用角色表示,比如ROLE_ADMINISTRATOR 或 ROLE_HR_SUPERVISOR。 这些角色会在后面,对web验证,方法验证和领域对象验证进行配置。 Spring Security的其他部分用来拦截这些权限,期望他们被表现出现。 GrantedAuthority对象通常使用UserDetailsService读取的。
通常情况下,GrantedAuthority对象是应用程序范围下的授权。 它们不会特意分配给一个特定的领域对象。 因此,你不能设置一个GrantedAuthority,让它有权限展示编号54的Employee对象,因为如果有成千上网的这种授权,你会很快用光内存(或者,至少,导致程序花费大量时间去验证一个用户)。 当然,Spring Security被明确设计成处理常见的需求,但是你最好别因为这个目的使用项目领域模型安全功能。
最后,但不是最不重要的,有时你需要在HTTP请求之间共享SecurityContext。 其他时候,主体会在每个请求里重新验证,虽然大多数情况下它可以存储。 HttpSessionContextIntegrationFilter就是实现在HTTP请求之间存储SecurityContext的。 就像它的类名一样,HttpSession被用来保存这些信息。 你不应该因为安全的问题,直接与HttpSession打交道。 根本不存在这样做的理由-一直使用SecurityContextHolder作替代方式。
5.2.4. 小结
简单回顾一下,Spring Security主要是由一下几部分组成的:
• SecurityContextHolder,提供几种访问SecurityContext的方式。
• SecurityContext,保存Authentication信息,和请求对应的安全信息。
• HttpSessionContextIntegrationFilter,为了在不同请求使用,把SecurityContext保存到 HttpSession里。
• Authentication,展示Spring Security特定的主体。
• GrantedAuthority,反应,在应用程序范围你,赋予主体的权限。
• UserDetails,通过你的应用DAO,提供必要的信息,构建Authentication对象。
• UserDetailsService,创建一个 UserDetails,传递一个 String类型的用户名(或者证书ID或其他)。
现在,你应该对这种重复使用的组件有一些了解了。 让我们贴近看一下验证的过程。
5.3. 验证
就像这篇指南开头提到的那样,Spring Security可在很多不同的验证环境下使用。 虽然我们推荐人们使用Spring Security,不与已存在的容器管理认证系统整合, 但它也是支持的-使用你自己的属性验证系统进行整合。 让我们先看看Spring Security完全依靠自己, 管理web安全,这里会演示最复杂和最常见的情况。
讨论一个典型的web应用验证过程:
• 你访问首页,点击一个链接。
• 向服务器发送一个请求,服务器判断你是否在访问一个受保护的资源。
• 如果你还没有进行过认证,服务器发回一个响应,提示你必须进行认证。 响应可能是HTTP响应代码,或者是重新定向到一个特定的web页面。
• 依据验证机制,你的浏览器将重定向到特定的web页面,这样你可以添加表单, 或者浏览器使用其他方式校验你的身份(比如,一个基本校验对话框,cookie,或者X509证书,或者其他)。
• 浏览器会发回一个响应给服务器。 这将是HTTP POST包含你填写的表单内容,或者是HTTP头部,包含你的验证信息。
• 下一步,服务器会判断当前的证书是否是有效的, 如果他们是有效的,下一步会执行。 如果他们是非法的,通常你的浏览器会再尝试一次(所以你返回的步骤二)。
• 你发送的原始请求,会导致重新尝试验证过程。 有希望的是,你会通过验证,得到足够的授权,访问被保护的资源。 如果你有足够的权限,请求会成功。否则,你会收到一个HTTP错误代码403,意思是访问被拒绝。
Spring Security使用鲜明的类负责上面提到的每个步骤。 主要的部分是(为了使用他们)是ExceptionTranslationFilter, 一个AuthenticationEntryPoint, 一个验证机制,一个AuthenticationProvider。
5.3.1. ExceptionTranslationFilter
ExceptionTranslationFilter 是一个Spring Security过滤器,用来检测是否抛出了Spring Security异常。 这些异常会被AbstractSecurityInterceptor抛出,它主要用来提供验证服务。 我们会在下一节讨论AbstractSecurityInterceptor,但是现在,我们只需要知道,它是用来生成Java异常,和知道跟HTTP没 啥关系,或者如何验证一个主体。 而ExceptionTranslationFilter提供这些服务,使用特点那个的响应,返回错误代码403(如果主题被验证了,但是权限不足-在上 边的步骤七),或者启动一个AuthenticationEntryPoint(如果主体没有认证,然后我们需要进入步骤三)。
5.3.2. AuthenticationEntryPoint
AuthenticationEntryPoint 对应中上面列表中的步骤三。 如你所想的,每个web应用程序都有默认的验证策略(好的,这可以在Spring Security里配置一切,但是让我们现在保持简单)。 每个主要验证系统会有它自己的AuthenticationEntryPoint实现, 会执行动作,如同步骤三里的描述一样。
在你的浏览器决定提交你的认证证书之后(使用HTTP表单发送或者是HTTP头), 服务器部分需要有一些东西来“收集”这些验证信息。 现在我们到了上述的第六步。 在Spring Security里,我们需要一个特定的名字,来描述从用户代码(通常是浏览器)收集验证信息的功能,这个名字就是“验证机制”。 在从用户代码哪里收集了验证细节之后,一个"Authentication 请求"对象会被AuthenticationProvider建立。
5.3.3. AuthenticationProvider
Spring Security认证过程的最后一个角色是AuthenticationProvider。 非常简单,这是跟获得Authentication请求对象相关的,决定它是否是有效的。 这个供应器或者抛出一个异常,或者返回一个完整的Authentication对象。 还记得我们的好朋友UserDetails和UserDetailsService吗? 如果不记得,回头看看前面的章节,刷新你的记忆。 大多数AuthenticationProvider都会要求UserDetailsService提供一个UserDetails对象。 像上面提到的那样,大多数程序会提供他们自己的UserDetailsService虽然一些可以使用Spring Security提供的JDBC和内存实现。 由此产生的UserDetails对象-特别是UserDetails中包含的GrantedAuthority[]-将被用来组装 Authentication对象。
在验证机制重新获得了组装好的Authentication对象以后,他会认为请求有 效,把Authentication放到SecurityContextHolder里,然后导致原始请求重审(第七步)。 另一方面,如果AuthenticationProvider驳回了请求,验证机制会让用户代码重试(第二步)。
5.3.4. 直接设置SecurityContextHolder的内容
虽 然这表述了一个典型的验证流程,但是好消息是Spring Security不在意你如何把一个Authentication放到SecurityContextHolder里的。 唯一关键的需求是SecurityContextHolder包含Authentication,用来表现一个主体,在 AbstractSecurityInterceptor之前验证请求的。
你可以(很多用户都这样做)写一个自己的过滤器或 MVC控制器来提供验证系统的交互,这些都不是基于Spring Security的。 比如,你也许使用容器管理验证,从ThreadLocal或JNDI里获得当前用户信息。 或者,你的公司可能有一个遗留系统,它是一个企业标准,你不能控制它
分享到:
评论
8 楼 jiangwubo 2012-05-25  
USERS:用户表
ROLE:角色表,存放ROLE_USERS,ROLE_ADMIN 之类的,是写死的
RESOURCE:资源表,存放访问的URL
USERS_ROLE:用户角色关联表
ROLE_RESOURCE:角色资源关联表
7 楼 leon.s.kennedy 2012-05-25  
jiangwubo 写道
<sec:authorize ifAllGranted="ROLE_USER">www.baidu.com</sec:authorize>

比如现在用户USER1 需要访问www.baidu.com,你就把USER1的权限设置为ROLE_USER,

ROLE_USER 这些权限本来就是写死的。
我不太理解你要实现怎样一个动态的配置。

对于一个被访问的资源URL,你写上
<sec:authorize ifAllGranted="ROLE_USER">www.baidu.com</sec:authorize>
也只是给这个URL 加上一把锁,至于你想让谁来访问,你把这把锁的钥匙给他就行了呀。


我没搞明白,您说的钥匙Role_user 可以维护吗
您说的那5张表我也有,我现在弄不懂5张表之间关系了
Role_user是存在角色表中的吗? 这么说角色表也是不可维护的了?
在下愚昧,恳请您加我qq459109544
向您学习探讨
6 楼 jiangwubo 2012-05-24  
<sec:authorize ifAllGranted="ROLE_USER">www.baidu.com</sec:authorize>

比如现在用户USER1 需要访问www.baidu.com,你就把USER1的权限设置为ROLE_USER,

ROLE_USER 这些权限本来就是写死的。
我不太理解你要实现怎样一个动态的配置。

对于一个被访问的资源URL,你写上
<sec:authorize ifAllGranted="ROLE_USER">www.baidu.com</sec:authorize>
也只是给这个URL 加上一把锁,至于你想让谁来访问,你把这把锁的钥匙给他就行了呀。
5 楼 leon.s.kennedy 2012-05-24  
jiangwubo 写道
leon.s.kennedy 写道
您如此配置<sec:authorize ifAllGranted="ROLE_USER">可以访问</sec:authorize>
把角色硬编码写在JSP里,那今后怎么维护角色?



这个跟你系统的角色设置有关
我的项目中系统角色是这样设计的
1.系统定义了不同的角色,如ROLE_USERS,ROLE_ADMIN,ROLE_SYSTEM,等等这些都是写死的,在系统中固定的权限,不能新增和修改
2 对系统中的访问资源URL 进行定义,把URL 跟上面定义好的角色关联,可以修改和编辑URL跟角色的关联,形成对资源的动态访问
有四个table
USERS:用户表
ROLE:角色表
RESOURCE:资源表,存放访问的URL
USERS_ROLE:用户角色关联表
ROLE_RESOURCE:角色资源关联表


我也是这5张表
现在需求是 用户 和 角色 和 角色资源 是可以维护的
如果JSP中写死了ROLE 标签控制显示url
那该角色是无法删除 或维护的
求解
4 楼 jiangwubo 2012-05-23  
leon.s.kennedy 写道
您如此配置<sec:authorize ifAllGranted="ROLE_USER">可以访问</sec:authorize>
把角色硬编码写在JSP里,那今后怎么维护角色?



这个跟你系统的角色设置有关
我的项目中系统角色是这样设计的
1.系统定义了不同的角色,如ROLE_USERS,ROLE_ADMIN,ROLE_SYSTEM,等等这些都是写死的,在系统中固定的权限,不能新增和修改
2 对系统中的访问资源URL 进行定义,把URL 跟上面定义好的角色关联,可以修改和编辑URL跟角色的关联,形成对资源的动态访问
有四个table
USERS:用户表
ROLE:角色表
RESOURCE:资源表,存放访问的URL
USERS_ROLE:用户角色关联表
ROLE_RESOURCE:角色资源关联表
3 楼 leon.s.kennedy 2012-05-21  
您如此配置<sec:authorize ifAllGranted="ROLE_USER">可以访问</sec:authorize>
把角色硬编码写在JSP里,那今后怎么维护角色?
2 楼 jiangwubo 2012-05-21  
<sec:authorize ifAllGranted="ROLE_USER">可以访问</sec:authorize> 这个只是用来限制JSP 页面中一些控件对哪些权限这可以操作。
不明白你具体的问题是什么? 你说的url 不是在这里控制的,那个应该在决策器里面设置
1 楼 leon.s.kennedy 2012-04-26  
博主您好
<sec:authorize ifAllGranted="ROLE_USER">可以访问</sec:authorize>
其中角色ROLE_USER 是写死的(硬编码)

这种情况是可以用的

系统角色是可以维护的,请问该如何实现?

还有url属性,如果写死在配置文件中,就可以用

url保存在DB中,页面标签url属性也不起作用了

求解决方案

相关推荐

    精彩:Spring Security 演讲PPT

    Spring Security 演讲PPT(演讲嘉宾:张明星) WebSphere技术专家沙龙在广州圆满举办,WSC超级版主Fastzch(张明星)担任本次沙龙的演讲嘉宾,他给广州的WebSphere技术专家带来了以“Spring Security ”为主题的...

    SpringSecurity.zip

    ​ Spring Security:spring家族一员。是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转...

    Spring Security 资料合集

    Spring Security三份资料,实战Spring Security 3.x.pdf;Spring Security 3.pdf;Spring Security使用手册.pdf

    Spring Security OAuth2.0学习笔记.zip

    Spring Security OAuth2.0学习笔记 什么是认证、授权、会话。 Java Servlet为支持http会话做了哪些事儿。 基于session认证机制的运作流程。 基于token认证机制的运作流程。 理解Spring Security的工作原理,Spring ...

    Spring Security实战源码

    该资源是基本Spring Security实战七篇文档中组织的源码,详情如下: ssecurity项目是Spring Security实战(一和二)的源码; ssecurity-db项目是Spring Security实战(三)的源码; ssceurity-page项目是Spring ...

    微信扫一扫登录、微信支付、springsecurity&oauth2

    项目中使用到的技术包含SpringBoot、SpringSecurity&oauth2(安全资源和授权中心模式、包括登录接口自定义返回字段、自定义手机号+密码登录、自定义免密登录)、Queue队列、线程池、xss攻击配置、SpringCache、Mybatis...

    Spring Security 参考手册Spring Security中文版

    很多独立软件供应商,因为灵活的身份验证模式二选择Spring Security。这样做允许他们快速的集成到他们的终端客户需求的解决方案而不用进行大量工程或者改变客户的环境。如果上面的验证机制不符合你的需求,Spring ...

    springsecurity原理流程图.pdf

    SpringSecurity框架的权限认证流程原理,请求到来时SpringSecurity如果调用层层过滤器来完成认证;

    spring spring security2.5 jar

    spring security2.5 jar 和spring security2.5 整合必须的jar包

    SpringSecurity项目

    springsecurity是一个功能强大且高度可定制的身份验证和访问控制框架。springsecurity是一个专注于为Java应用程序提供身份验证和授权的框架。与所有Spring项目一样,Spring安全性的真正威力在于它可以很容易地扩展以...

    Spring Security in Action

    Spring Security in Action

    Spring Cloud Gateway 整合 Spring Security 统一登录认证鉴权

    1.本项目为SpringCloud Gateway的微服务框架,整合了SpringSecurity,微服务间使用Redis来获取登陆的用户信息。 2.由于Gat

    spring security spring security

    spring security spring security 中文文档

    SpringSecurity.pdf

    SpringSecurity入门到进阶到高级,是我们老师给我们讲课用的,我们都照着配就没有问题,可以跑通,

    SpringSecurity课程文档下载 pdf 教学

    SpringSecurity课程文档下载 pdf 教学

    SpringSecurity学习总结源代码

    SpringSecurity学习总结源代码

    spring security 参考手册中文版

    Spring Security 参考 1 第一部分前言 15 1.入门 16 2.介绍 17 2.1什么是Spring Security? 17 2.2历史 19 2.3版本编号 20 2.4获得Spring安全 21 2.4.1使用Maven 21 Maven仓库 21 Spring框架 22 2.4.2 Gradle 23 ...

    spring security3 中文版本

    spring security3 中文版本

    安全框架Spring Security深入浅出视频教程

    视频详细讲解,需要的小伙伴自行网盘下载,链接见附件,永久有效。 首先,SSM环境中我们通过xml配置的...Springsecurity在两种不同的开发模式中使用,有经典的独立web后台管理系统,也有时下最流行的前后端分离场景。

    Spring Security 3.pdf

    Spring Security 3.pdf Spring Security 3.pdf Spring Security 3.pdf Spring Security 3.pdf

Global site tag (gtag.js) - Google Analytics