安全命名空间配置
自 Spring 框架 2.0 版本起,已提供了命名空间配置。
它允许您在传统 Spring 颗粒(bean)应用程序上下文语法中补充来自其他 XML 架构的元素。
您可以查阅 Spring 的 参考文档 获取更多信息。
您可以使用命名空间元素更简洁地配置一个单独的颗粒,或者更强大地定义一种替代的配置语法,使其更贴近问题领域,并从用户面前隐藏底层复杂性。
简单的元素可以掩饰多个颗粒和处理步骤被添加到应用程序上下文的事实。
例如,在应用上下文中添加以下来自 security 命名空间的元素将启动一个嵌入式 LDAP 服务器,用于在应用程序中进行测试使用:
<security:ldap-server />
这比手动连接等效的 UnboundID 服务器 bean 简单得多。
ldap-server 元素上的属性支持最常见的替代配置需求,用户无需担心需要创建哪些 bean 及其 bean 属性名称。
您可以参阅关于 LDAP 认证 章节以获取有关 ../authentication/passwords/ldap.html#servlet-authentication-ldap 元素使用的更多信息。在编辑应用上下文文件时,一个好的 XML 编辑器会提供可用属性和元素的信息。
我们推荐您尝试使用 Spring Tool Suite,因为它具有专门针对标准 Spring 命名空间的工作特性。
要开始在应用程序上下文中使用security命名空间,需要将spring-security-configjar添加到类路径中。
然后,您只需要向应用程序上下文文件中添加模式声明即可:
<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
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd">
...
</beans>
在许多示例中,您可以看到(并在样本应用程序中),我们通常使用security(而不是beans)作为默认命名空间,这意味着我们可以省略所有安全命名空间元素的前缀,从而使内容更易于阅读。
如果您将应用程序上下文分成多个文件,并且大部分的安全配置都在其中一个文件中,您也可以这样做。
您的安全应用上下文文件可能会这样开始:
<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
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
https://www.springframework.org/schema/security/spring-security.xsd">
...
</beans:beans>
我们从这一章开始假设使用这种语法。
命名空间设计
该命名空间旨在捕捉框架中最常见的用途,并提供在应用程序中启用它们的简化和简洁语法。 设计基于框架中的大型依赖关系,并可以分为以下几个区域:
-
Web/HTTP 安全是最复杂的部分。 它设置了用于应用框架认证机制、保护 URL、渲染登录和错误页面等相关服务 bean 的过滤器。
-
业务对象(方法)安全定义了用于保护服务层的选项。
-
AuthenticationManager 处理来自框架其他部分的认证请求。
-
AccessDecisionManager 为网络和方法安全提供访问决策。 默认会注册一个,但你可以选择使用一个自定义的,通过标准的Spring bean语法进行声明。
-
AuthenticationProvider 实例提供机制,用于认证管理器对用户进行身份验证。 命名空间提供了对多种标准选项的支持,并且可以添加自定义的 bean,这些 bean 是通过传统语法声明的。
-
UserDetailsService与认证提供者关系密切,但也经常被其他bean所需。
我们将在以下部分了解如何配置这些内容。
开始使用安全命名空间配置
此部分介绍了如何构建命名空间配置,以利用框架的一些主要功能。<br> 我们假设您最初希望尽快启动并运行,并为现有Web应用程序添加身份验证支持和访问控制,同时进行一些测试登录。<br> 然后我们将探讨如何切换到通过数据库或其他安全存储库进行身份验证。<br> 在后续部分中,我们将介绍更高级的命名空间配置选项。
web.xml 配置
您需要做的第一件事是将以下过滤器声明添加到您的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>
DelegatingFilterProxy是Spring框架的一个类,它将调用一个由Spring应用上下文中的某个bean定义的过滤器实现。
在这个例子中,这个bean的名字是springSecurityFilterChain,这是一个由命名空间创建的内部基础设施bean,用于处理网络安全性。
注意,你不应该自己使用这个名字的bean。
一旦你将这个bean添加到你的web.xml中,你就准备好开始编辑你的应用上下文文件了。
网络安全性服务通过<http>元素进行配置。
一个最小化的 <http> 配置
要启用Web安全,您需要以下配置:
<http>
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>
那个列表说我们想要:
-
我们的应用程序中所有需要被安全保护的URL,需要具有
ROLE_USER角色才能访问它们 -
使用表单以用户名和密码登录应用程序
-
注册了一个注销URL,允许我们从应用程序中登出
<http> 元素是所有与网络相关命名空间功能的父元素。<intercept-url> 元素定义了一个 pattern,该元素使用 Ant 路径语法匹配传入请求的 URL。有关匹配实际执行方式的更多详细信息,请参阅 HttpFirewall 部分。你也可以使用正则表达式匹配作为替代方案(更多细节请参见命名空间附录)。access 属性定义了与给定模式匹配的请求的访问要求。在默认配置下,这通常是角色的逗号分隔列表,只有当用户具有其中一个角色时才能允许其进行请求。ROLE_前缀是一个标记,表示应针对用户的权限进行简单比较。换句话说,应该使用正常的基于角色的检查。Spring Security 的访问控制不限于使用简单的角色(因此使用前缀来区分不同类型的安全属性)。我们稍后会看到这种解释可能会有所不同。access 属性中逗号分隔值的解释取决于所使用的 AccessDecisionManager 实现。自从 Spring Security 3 版本起。0,您还可以使用 EL 表达式 来填充该属性。
|
您可以通过多个 |
要添加用户,您可以在命名空间中直接定义一组测试数据:
<authentication-manager>
<authentication-provider>
<user-service>
<!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that
NoOpPasswordEncoder should be used. This is not safe for production, but makes reading
in samples easier. Normally passwords should be hashed using BCrypt -->
<user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
前一个列表展示了一种安全存储相同密码的方法。
该密码以 {bcrypt} 前缀开始,指示 DelegatingPasswordEncoder(它支持任何配置的 PasswordEncoder 用于匹配),这些密码是使用 BCrypt 进行哈希处理的:
<authentication-manager>
<authentication-provider>
<user-service>
<user name="jimi" password="{bcrypt}$2a$10$ddEWZUl8aU0GdZPPpy7wbu82dvEw/pBpbRvDQRqA41y6mK1CoH00m"
authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="{bcrypt}$2a$10$/elFpMBnAYYig6KRR5bvOOYeZr1ie1hSogJryg9qDlhza4oCw1Qka"
authorities="ROLE_USER" />
<user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
前面的配置定义了两个用户、他们的密码以及他们在应用程序中的角色(这些信息用于访问控制)。
您可以将用户信息从标准属性文件中加载,通过在properties元素上设置user-service属性来实现。
有关文件格式的详细信息,请参阅关于内存中的身份验证的部分。
使用<authentication-provider>元素意味着用户信息将被认证管理器用于处理认证请求。
您可以有多个<authentication-provider>元素来定义不同的认证来源。每个来源都会依次被查询。
现在已经可以启动你的应用程序了,你应该需要登录才能继续。 你可以试试看,或者尝试一下项目自带的“教程”样例应用。
设置默认登录后跳转目标
如果尝试访问受保护的资源时未提示表单登录,则 default-target-url 选项将生效。
这是用户成功登录后被引导至的 URL。其默认值为 /。
您还可以通过将 always-use-default-target 属性设置为 true,配置系统使用户始终跳转到此页面(无论登录是“按需触发”还是用户主动选择登录)。
如果您的应用程序始终要求用户从“主页”开始,此功能非常有用,例如:
<http pattern="/login.htm*" security="none"/>
<http use-expressions="false">
<intercept-url pattern='/**' access='ROLE_USER' />
<form-login login-page='/login.htm' default-target-url='/home.htm'
always-use-default-target='true' />
</http>
为了对目标有更多控制,您可以使用authentication-success-handler-ref属性作为default-target-url的替代方案。
引用的bean应该是一个AuthenticationSuccessHandler实例。
高级 Web 功能
本节涵盖了各种超越基础功能的特性。
添加您自己的过滤器
如果之前使用过Spring Security,你可能知道该框架维护了一条过滤器链,用于应用其服务。
你可能希望在特定位置添加自己的过滤器到栈中,或者使用目前没有命名空间配置选项的Spring Security过滤器(例如CAS)。
另外,你可能还想使用标准命名空间过滤器的一个自定义版本,比如UsernamePasswordAuthenticationFilter(由<form-login>元素创建),以便利用显式使用bean时提供的额外配置选项。
如何通过命名空间配置来实现这一点,因为过滤器链并没有直接暴露出来呢?
当您使用命名空间时,过滤器的顺序总是严格遵守。 在应用程序上下文被创建时,过滤器豆由命名空间处理代码进行排序,并且标准Spring Security过滤器每个都有一个在命名空间中的别名和一个众所周知的位置。
|
在之前的版本中,排序是在过滤器实例创建之后,在应用程序上下文的后处理阶段进行。
在3.0+版本中,排序现在在bean元数据级别进行,即在类实例化之前。
这对你如何将自定义过滤器添加到堆栈有影响,因为必须在解析 |
过滤器、别名和命名空间元素及其创建过滤器的元素和属性显示在以下表格中,按照它们在过滤链中的顺序排列:
| 别名 | 过滤器类 | namespace 元素或属性 |
|---|---|---|
DISABLE_ENCODE_URL_FILTER |
|
|
FORCE_EAGER_SESSION_FILTER |
|
|
CHANNEL_FILTER |
|
|
SECURITY_CONTEXT_FILTER |
|
|
CONCURRENT_SESSION_FILTER |
|
|
HEADERS_FILTER |
|
|
CSRF_FILTER |
|
|
LOGOUT_FILTER |
|
|
X509_FILTER |
|
|
PRE_AUTH_FILTER |
|
N/A |
CAS_FILTER |
|
N/A |
FORM_LOGIN_FILTER |
|
|
BASIC_AUTH_FILTER |
|
|
SERVLET_API_SUPPORT_FILTER |
|
|
JAAS_API_SUPPORT_FILTER |
|
|
REMEMBER_ME_FILTER |
|
|
ANONYMOUS_FILTER |
|
|
SESSION_MANAGEMENT_FILTER |
|
|
EXCEPTION_TRANSLATION_FILTER |
|
|
FILTER_SECURITY_INTERCEPTOR |
|
|
SWITCH_USER_FILTER |
|
N/A |
您可以使用custom-filter元素和这些名称之一来指定您的过滤器应在堆栈中的哪个位置出现:
<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>
您还可以使用after或before属性,如果希望您的过滤器在过滤器堆栈中的其他过滤器之前或之后插入。
您可以使用FIRST和LAST与position属性一起使用,以指示您希望您的过滤器出现在整个堆栈之前或之后。
|
避免过滤器位置冲突
如果您插入自定义过滤器,该过滤器可能与命名空间创建的标准过滤器占据相同的位置,请勿意外包含命名空间版本。 移除任何您想要替换其功能的过滤器元素。 注意,您无法替换通过使用 |
如果您替换了一个需要身份验证入口点的命名空间过滤器(即,当未认证用户尝试访问受保护资源时触发的身份验证过程),则也需要添加一个自定义入口点 bean。
方法安全
自版本2.0起,Spring Security 对服务层方法的安全性添加提供了显著支持。它提供了对JSR-250注解安全的支持以及框架原有的@Secured注解。
从版本3.0开始,您还可以利用基于表达式的注解。
您可以单独应用安全设置(通过使用intercept-methods元素来装饰bean声明),或者在整个服务层中跨多个bean使用AspectJ风格的切点进行安全控制。
默认访问决策管理器
此部分假设您对Spring Security中的访问控制底层架构有所了解。 如果您不了解,请跳过这一部分,稍后返回阅读。只有需要进行一些自定义以使用超过基于角色的安全机制的人才与之相关。
当您使用命名空间配置时,会自动为您注册一个默认的AccessDecisionManager实例,并根据您在intercept-url和protect-pointcut声明中(以及如果使用注解来保护方法时,在注解中)指定的访问属性来为方法调用和Web URL访问做出访问决策。
The default strategy is to use an AffirmativeBased AccessDecisionManager with a RoleVoter and an AuthenticatedVoter.
You can find out more about these in the chapter on 授权.
自定义 AccessDecisionManager
如果需要使用更复杂的访问控制策略,您可以为方法和Web安全设置替代方案。
对于方法安全设置,您可以通过在access-decision-manager-ref上设置global-method-security属性来实现,将其设置为应用程序上下文中相应id bean的AccessDecisionManager:
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>
Web安全的语法是相同的,但属性位于http元素上:
<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>