安全命名空间配置
命名空间配置从 Spring Framework 的 2.0 版开始就可用。
它允许您使用其他 XML 模式中的元素来补充传统的 Spring bean 应用程序上下文语法。
您可以在 Spring 参考文档中找到更多信息。
您可以使用名称空间元素来更简洁地配置单个 Bean,或者更强大地定义一种替代配置语法,该语法更紧密地匹配问题域,并向用户隐藏底层复杂性。
一个简单的元素可以掩盖将多个 bean 和处理步骤添加到应用程序上下文中的事实。
例如,将命名空间中的以下元素添加到应用程序上下文将启动嵌入式 LDAP 服务器,以便在应用程序中进行测试使用:security
<security:ldap-server />
这比连接等效的 Apache Directory Server Bean 要简单得多。
元素上的属性支持最常见的替代配置要求,并且用户无需担心他们需要创建哪些 bean 以及 bean 属性名称是什么。
您可以在 LDAP 身份验证一章中找到有关该元素使用的更多信息。
在编辑应用程序上下文文件时,一个好的 XML 编辑器应该提供有关可用属性和元素的信息。
我们建议您尝试 Spring Tool Suite,因为它具有使用标准 Spring 命名空间的特殊功能。ldap-server
ldap-server
要开始在应用程序上下文中使用命名空间,请将 jar 添加到你的 Classpath 中。
然后,您需要做的就是将 schema 声明添加到您的应用程序上下文文件中:security
spring-security-config
<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 安全是最复杂的部分。 它设置了用于应用框架身份验证机制的过滤器和相关服务 bean,以保护 URL、呈现登录页和错误页等等。
-
业务对象(方法)安全性 定义用于保护服务层的选项。
-
AuthenticationManager 处理来自框架其他部分的身份验证请求。
-
AccessDecisionManager 为 Web 和方法安全提供访问决策。 默认的 bean 是已注册的,但您可以选择使用自定义的 bean 语法,使用普通的 Spring bean 语法声明。
-
AuthenticationProvider 实例提供身份验证管理器对用户进行身份验证的机制。 名称空间提供了对多个标准选项的支持,以及添加使用传统语法声明的自定义 bean 的方法。
-
UserDetailsService与身份验证提供程序密切相关,但其他 bean 通常也需要它。
我们将在以下部分中了解如何配置这些 API。
Security Namespace Configuration 入门
本节将介绍如何构建命名空间配置以使用框架的一些主要功能。 我们假设您最初希望尽快启动并运行,并通过几次测试登录向现有 Web 应用程序添加身份验证支持和访问控制。 然后,我们看看如何切换到针对数据库或其他安全存储库进行身份验证。 在后面的部分中,我们将介绍更高级的命名空间配置选项。
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>
DelegatingFilterProxy
是一个 Spring Framework 类,它委托给在应用程序上下文中定义为 Spring Bean 的过滤器实现。
在这种情况下,Bean 名为 ,这是由名称空间创建的用于处理 Web 安全性的内部基础结构 Bean。
在这种情况下,该 Bean 被命名为“springSecurityFilterChain”,这是由名称空间创建的用于处理 Web 安全性的内部基础结构 Bean。
请注意,您自己不应使用此 bean 名称。
将此 bean 添加到 后,您就可以开始编辑应用程序上下文文件了。
Web 安全服务由 element 配置。springSecurityFilterChain
web.xml
<http>
最小 <http> 配置
要启用 Web 安全,您需要以下配置:
<http>
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>
该列表显示我们想要:
-
我们应用程序中的所有 URL 都受到保护,需要角色访问它们
ROLE_USER
-
使用包含用户名和密码的表单登录应用程序
-
已注册的注销 URL,这将允许我们注销应用程序
该元素是所有与 Web 相关的命名空间功能的父级。
该元素定义一个 ,该 使用 Ant 路径语法与传入请求的 URL 进行匹配。请参阅 HttpFirewall
部分 以了解有关实际如何执行匹配的更多详细信息。
您还可以使用正则表达式匹配作为替代方法(有关更多详细信息,请参阅 namespace appendix)。
该属性定义与给定模式匹配的请求的访问要求。
使用默认配置时,这通常是一个以逗号分隔的角色列表,必须允许用户发出请求。
前缀是一个标记,指示应与用户的权限进行简单比较。
换句话说,应该使用正常的基于角色的检查。
Spring Security 中的访问控制不仅限于使用简单的角色(因此使用前缀来区分不同类型的安全属性)。
我们稍后会看到解释是如何变化的。属性中逗号分隔值的解释取决于使用的 AccessDecisionManager
的实现。
从 Spring Security 3.0 开始,您还可以使用 EL 表达式填充属性。<http>
<intercept-url>
pattern
access
ROLE_
access
您可以使用多个元素为不同的 URL 集定义不同的访问要求,但会按列出的顺序对它们进行评估,并使用第一个匹配项。
因此,您必须将最具体的匹配项放在顶部。
您还可以添加属性以将匹配项限制为特定的 HTTP 方法(、、 、 等)。 |
要添加用户,您可以直接在命名空间中定义一组测试数据:
<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>
前面的清单显示了存储相同密码的安全方法的示例。
密码前缀为 to instruct ,它支持任何配置为匹配的密码,使用 BCrypt 对密码进行哈希处理:{bcrypt}
DelegatingPasswordEncoder
PasswordEncoder
<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>
前面的配置定义了两个用户、他们的密码及其在应用程序中的角色(用于访问控制)。
您还可以通过在元素上设置属性来从标准属性文件加载用户信息。
请参阅 内存身份验证 有关文件格式的更多详细信息。
使用该元素意味着认证管理器使用用户信息来处理认证请求。
您可以使用多个元素来定义不同的身份验证源。每个 Cookie 依次进行咨询。properties
user-service
<authentication-provider>
<authentication-provider>
此时,您应该能够启动您的应用程序,并且应该需要登录才能继续。 尝试一下,或者尝试使用项目附带的 “tutorial” 示例应用程序进行试验。
设置默认登录后目标
如果尝试访问受保护资源时未提示表单登录,则该选项将起作用。
这是用户成功登录后将转到的 URL。它默认为 。
您还可以通过将属性设置为 来配置内容,以便用户始终以此页面结束(无论登录是“按需”登录还是他们明确选择登录)。
如果您的应用程序始终要求用户从 “home” 页面开始,则这非常有用,例如:default-target-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>
要更好地控制目标,可以使用 该属性作为 .
引用的 Bean 应该是 的实例。authentication-success-handler-ref
default-target-url
AuthenticationSuccessHandler
高级 Web 功能
本节介绍除基础知识之外的各种功能。
添加您自己的过滤器
如果您以前使用过 Spring Security,那么您就会知道该框架维护着一个过滤器链,用于应用其服务。
您可能希望将自己的过滤器添加到特定位置的堆栈中,或者使用当前没有命名空间配置选项(例如 CAS)的 Spring Security 过滤器。
或者,您可能希望使用标准名称空间过滤器的自定义版本,例如(由元素创建)以利用显式使用 bean 时可用的一些额外配置选项。
既然过滤器链没有直接公开,你怎么能用命名空间配置来做到这一点呢?UsernamePasswordAuthenticationFilter
<form-login>
使用命名空间时,始终严格执行筛选器的顺序。 在创建应用程序上下文时,过滤器 bean 按名称空间处理代码进行排序,并且标准 Spring Security 过滤器在名称空间中都有一个别名和一个众所周知的位置。
在以前的版本中,排序是在创建 filter 实例之后,在应用程序上下文的后处理期间进行的。
在 3.0+ 版本中,排序现在是在 bean 元数据级别完成的,在实例化类之前。
这对如何将自己的过滤器添加到堆栈有影响,因为在解析元素期间必须知道整个过滤器列表,因此在 3.0 中语法略有变化。 |
下表显示了创建过滤器的过滤器、别名以及命名空间元素和属性,并按它们在过滤器链中出现的顺序显示:
别名 | Filter 类 | 命名空间元素或属性 |
---|---|---|
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 |
|
不适用 |
CAS_FILTER |
|
不适用 |
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 |
|
不适用 |
您可以使用元素和以下名称之一来指定过滤器的显示位置,从而将自己的过滤器添加到堆栈中:custom-filter
<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>
如果您希望将筛选条件插入到堆栈中的另一个筛选条件之前或之后,也可以使用 or 属性。
您可以将 和 与属性一起使用,以指示您希望筛选条件分别显示在整个堆栈之前或之后。after
before
FIRST
LAST
position
避免过滤器位置冲突
如果插入的自定义过滤器可能与命名空间创建的标准过滤器之一占据相同的位置,则不应错误地包含命名空间版本。 删除任何创建要替换其功能的过滤器的元素。 请注意,您无法替换通过使用元素本身创建的过滤器: 、 或 。
默认情况下,会添加 an,除非您禁用了会话固定保护,否则还会将 a 添加到过滤器链中。 |
如果替换需要身份验证入口点的名称空间过滤器(即,身份验证过程由未经身份验证的用户尝试访问受保护资源触发),则还需要添加自定义入口点 Bean。
方法安全性
从版本 2.0 开始, Spring Security 对向服务层方法添加安全性提供了大量支持。
它提供对 JSR-250 注释安全性以及框架的原始注释的支持。
从版本 3.0 开始,您还可以使用基于表达式的注释。
你可以将安全性应用于单个 bean(通过使用元素来装饰 bean 声明),或者你可以使用 AspectJ 样式的切入点在整个服务层中保护多个 bean。@Secured
intercept-methods
默认的 AccessDecisionManager
本节假定您对 Spring Security 中访问控制的底层架构有一定的了解。 如果不这样做,则可以跳过它,稍后再返回它,因为本节仅与需要进行一些自定义以使用不仅仅是简单的基于角色的安全性的人相关。
当您使用命名空间配置时,将自动为您注册一个默认实例,并用于根据您在 and 声明中指定的访问属性(以及在注释中,如果您使用注释来保护方法)指定的访问属性,为方法调用和 Web URL 访问做出访问决策。AccessDecisionManager
intercept-url
protect-pointcut
默认策略是将 an 与 a 和 .
您可以在授权章节中了解有关这些内容的更多信息。AffirmativeBased
AccessDecisionManager
RoleVoter
AuthenticatedVoter
自定义 AccessDecisionManager
如果您需要使用更复杂的访问控制策略,您可以为方法和 Web 安全性设置替代方案。
为了方法安全性,你可以通过在应用程序上下文中将属性on设置为适当的 bean 来实现:access-decision-manager-ref
global-method-security
id
AccessDecisionManager
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>
Web 安全性的语法是相同的,但属性位于元素上:http
<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>