对于最新的稳定版本,请使用 Spring Security 6.5.3! |
安全命名空间配置
介绍
命名空间配置从 Spring Framework 2.0 版开始就可用。 它允许您使用其他 XML 模式中的元素来补充传统的 Spring Bean 应用程序上下文语法。 您可以在 Spring 参考文档中找到更多信息。 命名空间元素可以简单地用于允许以更简洁的方式配置单个 bean,或者更强大的是定义一种替代配置语法,该语法更接近问题域并向用户隐藏底层复杂性。 一个简单的元素可能会隐藏多个 bean 和处理步骤正在添加到应用程序上下文中的事实。 例如,将以下元素从安全命名空间添加到应用程序上下文将启动嵌入式 LDAP 服务器以测试在应用程序中的使用:
<security:ldap-server />
这比连接等效的 Apache Directory Server bean 要简单得多。
最常见的替代配置要求由ldap-server
元素,用户无需担心他们需要创建哪些 bean 以及 bean 属性名称是什么。[1].].
在编辑应用程序上下文文件时使用良好的 XML 编辑器应提供有关可用属性和元素的信息。
我们建议您尝试使用 Spring Tools 的 Eclipse IDE,因为它具有使用标准 Spring 命名空间的特殊功能。
要开始在应用程序上下文中使用安全命名空间,您需要具有spring-security-config
jar 的 jar 在您的类路径上。
然后,您需要做的就是将模式声明添加到应用程序上下文文件中:
<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”而不是“bean”作为默认命名空间,这意味着我们可以省略所有安全命名空间元素上的前缀,使内容更易于阅读。 如果将应用程序上下文划分为单独的文件,并且大部分安全配置都在其中一个文件中,则可能还需要执行此作。 然后,您的安全应用程序上下文文件将像这样启动
<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 和方法安全性的访问决策。 将注册一个默认的,但您也可以选择使用使用普通 Spring bean 语法声明的自定义一个。
-
AuthenticationProviders - 身份验证管理器对用户进行身份验证的机制。 命名空间提供了对多个标准选项的支持,也提供了一种添加使用传统语法声明的自定义 Bean 的方法。
-
UserDetailsService - 与身份验证提供者密切相关,但通常也需要其他 bean。
我们将在以下部分中了解如何配置这些内容。
安全命名空间配置入门
在本节中,我们将了解如何构建命名空间配置以使用框架的一些主要功能。 假设您最初希望尽快启动和运行,并通过一些测试登录向现有 Web 应用程序添加身份验证支持和访问控制。 然后,我们将研究如何转换为针对数据库或其他安全存储库进行身份验证。 在后面的部分中,我们将介绍更高级的命名空间配置选项。
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>
这提供了对 Spring Security Web 基础架构的钩子。DelegatingFilterProxy
是一个 Spring Framework 类,它委托给过滤器实现,该过滤器实现在您的应用程序上下文中被定义为 Spring Bean。在这种情况下,bean 被命名为“springSecurityFilterChain”,它是命名空间为处理 Web 安全性而创建的内部基础设施 bean。请注意,您不应该自己使用此 bean 名称。一旦您将此添加到您的web.xml
,您就可以开始编辑应用程序上下文文件了。Web 安全服务是使用<http>
元素。
最小的 <http> 配置
首先,启用 Web 安全所需的只是
<http>
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>
这表示我们希望应用程序中的所有 URL 都受到保护,因此需要角色ROLE_USER
要访问它们,我们希望使用带有用户名和密码的表单登录应用程序,并且我们需要注册一个注销 URL,这将允许我们注销应用程序。<http>
元素是所有与 Web 相关的命名空间功能的父级。 这<intercept-url>
元素定义了一个pattern
它使用 ant 路径样式语法与传入请求的 URL 进行匹配[2]有关实际如何执行匹配的更多详细信息。您还可以使用正则表达式匹配作为替代方法(有关更多详细信息,请参阅命名空间附录)。 这access
属性定义了与给定模式匹配的请求的访问要求。在默认配置中,这通常是一个以逗号分隔的角色列表,必须允许用户发出请求。前缀“ROLE_”是一个标记,表示应该与用户的权限进行简单的比较。换句话说,应该使用正常的基于角色的检查。Spring Security 中的访问控制不仅限于使用简单的角色(因此使用前缀来区分不同类型的安全属性)。我们稍后将看到解释如何变化[3]. 在 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,您就会知道该框架维护了一条过滤器链以应用其服务。
您可能希望将自己的过滤器添加到特定位置的堆栈中,或者使用当前没有命名空间配置选项(例如 CAS)的 Spring Security 过滤器。
或者,您可能想要使用标准命名空间过滤器的自定义版本,例如UsernamePasswordAuthenticationFilter
由<form-login>
元素,利用显式使用 bean 提供的一些额外配置选项。
既然过滤器链没有直接公开,你如何使用命名空间配置来做到这一点?
使用命名空间时,始终严格执行过滤器的顺序。 创建应用程序上下文时,过滤器 bean 按命名空间处理代码排序,并且每个标准 Spring Security 过滤器在命名空间中都有一个别名和一个已知位置。
在以前的版本中,排序是在创建过滤器实例后,在应用程序上下文的后处理期间进行的。
在版本 3.0+ 中,排序现在是在 bean 元数据级别完成的,在类实例化之前。
这对如何将自己的过滤器添加到堆栈有影响,因为在解析 |
创建过滤器的过滤器、别名和命名空间元素/属性显示在标准过滤器别名和排序中。 过滤器按它们在过滤器链中出现的顺序列出。
别名 | 过滤器类 | 命名空间元素或属性 |
---|---|---|
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"/>
您还可以使用after
或before
属性,如果您希望在堆栈中的另一个过滤器之前或之后插入过滤器。
名称“FIRST”和“LAST”可以与position
属性,以指示您希望过滤器分别出现在整个堆栈之前或之后。
避免过滤器位置冲突
如果您要插入的自定义过滤器可能与命名空间创建的标准过滤器之一占据相同的位置,那么请务必不要错误地包含命名空间版本。 删除创建要替换其功能的过滤器的任何元素。 请注意,您无法替换通过使用 |
如果您要替换需要身份验证入口点的命名空间过滤器(即身份验证过程是由未经身份验证的用户尝试访问安全资源触发的),您还需要添加自定义入口点 Bean。
方法安全性
从版本 2.0 开始,Spring Security 大大改进了对向服务层方法添加安全性的支持。
它提供了对 JSR-250 注释安全性以及框架原始@Secured
注解。
从 3.0 开始,您还可以使用新的基于表达式的注释。
您可以使用intercept-methods
元素来装饰 bean 声明,或者您可以使用 AspectJ 样式切入点保护整个服务层中的多个 bean。
默认 AccessDecisionManager
本节假设您对 Spring Security 中访问控制的底层体系结构有一定的了解。 如果不这样做,可以跳过它并稍后再回来,因为本节仅与需要进行一些自定义以使用简单的基于角色的安全性的人员真正相关。
使用命名空间配置时,默认实例AccessDecisionManager
会自动为您注册,并将用于根据您在intercept-url
和protect-pointcut
声明(如果您使用的是注释安全方法,则在注释中)。
默认策略是使用AffirmativeBased
AccessDecisionManager
使用RoleVoter
和AuthenticatedVoter
.
您可以在授权一章中找到有关这些内容的更多信息。
自定义 AccessDecisionManager
如果您需要使用更复杂的访问控制策略,那么很容易为方法和 Web 安全设置替代方案。
为了方法安全,您可以通过将access-decision-manager-ref
属性global-method-security
到id
适当的AccessDecisionManager
bean 在应用程序上下文中:
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>
Web 安全的语法是相同的,但在http
元素:
<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>
ldap-server
xref 中的元素:servlet/authentication/unpwd/ldap.adoc#servlet-authentication-ldap[LDAP 认证