安全命名空间配置

命名空间配置自 Spring Framework 2.0 版以来一直可用。它允许您使用额外 XML 模式中的元素补充传统的 Spring bean 应用程序上下文语法。您可以在 Spring 参考文档中找到更多信息。您可以使用命名空间元素更简洁地配置单个 bean,或者更强大地,定义一种更符合问题领域并向用户隐藏底层复杂性的替代配置语法。一个简单的元素可以隐藏将多个 bean 和处理步骤添加到应用程序上下文的事实。例如,将以下来自 security 命名空间的元素添加到应用程序上下文会启动一个嵌入式 LDAP 服务器,供应用程序内测试使用

<security:ldap-server />

这比连接等效的 UnboundID 服务器 bean 简单得多。最常见的替代配置要求由 ldap-server 元素上的属性支持,用户无需担心需要创建哪些 bean 以及 bean 属性名称是什么。您可以在关于 LDAP 认证的章节中找到有关 ldap-server 元素使用的更多信息。一个好的 XML 编辑器在编辑应用程序上下文文件时应该提供有关可用属性和元素的信息。我们建议您尝试 Spring Tool Suite,因为它具有处理标准 Spring 命名空间的特殊功能。

要开始在应用程序上下文中使用 security 命名空间,请将 spring-security-config 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(而不是 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 和方法安全提供访问决策。默认的管理器已注册,但您可以选择使用自定义管理器,使用普通 Spring bean 语法声明。

  • AuthenticationProvider 实例提供认证管理器用于认证用户的机制。命名空间支持几种标准选项以及添加使用传统语法声明的自定义 bean 的方法。

  • UserDetailsService 与认证提供者密切相关,但通常也为其他 bean 所需。

我们将在以下各节中介绍如何配置这些内容。

Spring Security 命名空间配置入门

本节将介绍如何构建命名空间配置以使用框架的一些主要功能。我们假设您最初希望尽快启动并运行,并向现有 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>

DelegatingFilterProxy 是一个 Spring Framework 类,它将请求委托给在应用程序上下文中定义为 Spring bean 的过滤器实现。在这种情况下,该 bean 名为 springSecurityFilterChain,它是由命名空间创建的一个内部基础设施 bean,用于处理 Web 安全。在这种情况下,该 bean 名为“springSecurityFilterChain”,它是命名空间创建的用于处理 Web 安全的内部基础设施 bean。请注意,您不应自行使用此 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 进行匹配。有关如何实际执行匹配的更多详细信息,请参阅关于 HttpFirewall 的部分。您也可以使用正则表达式匹配作为替代(有关更多详细信息,请参阅命名空间附录)。access 属性定义了与给定模式匹配的请求的访问要求。使用默认配置,这通常是一个逗号分隔的角色列表,用户必须拥有其中一个角色才能被允许发出请求。ROLE_ 前缀是一个标记,指示应与用户的权限进行简单比较。换句话说,应使用正常的基于角色的检查。Spring Security 中的访问控制不限于使用简单角色(因此使用前缀来区分不同类型的安全属性)。我们稍后会看到解释如何变化。access 属性中逗号分隔值的解释取决于使用哪个 AccessDecisionManager 实现。自 Spring Security 3.0 起,您还可以使用 EL 表达式填充该属性。

您可以使用多个 <intercept-url> 元素来为不同的 URL 集定义不同的访问要求,但它们按列出的顺序进行评估,并使用第一个匹配项。因此,您必须将最具体的匹配项放在顶部。您还可以添加一个 method 属性,将匹配限制为特定的 HTTP 方法(GETPOSTPUT 等)。

要添加用户,您可以直接在命名空间中定义一组测试数据

<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>

<http> 元素负责创建 FilterChainProxy 及其使用的过滤器 bean。以前常见的问题(例如不正确的过滤器顺序)不再是问题,因为过滤器位置是预定义的。

<authentication-provider> 元素创建一个 DaoAuthenticationProvider bean,而 <user-service> 元素创建一个 InMemoryDaoImpl。所有 authentication-provider 元素都必须是 <authentication-manager> 元素的子元素,该元素创建一个 ProviderManager 并向其注册认证提供者。您可以在命名空间附录中找到有关创建的 bean 的更详细信息。如果您想开始了解框架中的重要类及其使用方式,特别是如果您想以后自定义事物,则应交叉检查此附录。

前面的配置定义了两个用户、他们的密码以及他们在应用程序中的角色(用于访问控制)。您还可以通过设置 user-service 元素上的 properties 属性,从标准属性文件中加载用户信息。有关文件格式的更多详细信息,请参阅关于内存认证的部分。使用 <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 时可用的一些额外配置选项。如何使用命名空间配置来实现这一点,因为过滤器链没有直接公开?

使用命名空间时,过滤器的顺序始终严格执行。当应用程序上下文创建时,过滤器 bean 由命名空间处理代码排序,并且标准 Spring Security 过滤器在命名空间中都有一个别名和众所周知的位置。

在早期版本中,排序发生在过滤器实例创建之后,即应用程序上下文的后处理期间。在 3.0+ 版本中,排序现在在 bean 元数据级别完成,在类实例化之前。这对于您如何将自己的过滤器添加到堆栈中具有影响,因为在解析 <http> 元素期间必须知道整个过滤器列表,因此语法在 3.0 中略有更改。

以下表格显示了过滤器、别名以及创建这些过滤器的命名空间元素和属性,按它们在过滤器链中出现的顺序排列

表 1. 标准过滤器别名和顺序
别名 过滤器类 命名空间元素或属性

DISABLE_ENCODE_URL_FILTER

DisableEncodeUrlFilter

http@disable-url-rewriting

FORCE_EAGER_SESSION_FILTER

ForceEagerSessionCreationFilter

http@create-session="ALWAYS"

CHANNEL_FILTER

ChannelProcessingFilter

http/intercept-url@requires-channel

SECURITY_CONTEXT_FILTER

SecurityContextPersistenceFilter

http

CONCURRENT_SESSION_FILTER

ConcurrentSessionFilter

session-management/concurrency-control

HEADERS_FILTER

HeaderWriterFilter

http/headers

CSRF_FILTER

CsrfFilter

http/csrf

LOGOUT_FILTER

LogoutFilter

http/logout

X509_FILTER

X509AuthenticationFilter

http/x509

PRE_AUTH_FILTER

AbstractPreAuthenticatedProcessingFilter 子类

不适用

CAS_FILTER

CasAuthenticationFilter

不适用

FORM_LOGIN_FILTER

UsernamePasswordAuthenticationFilter

http/form-login

BASIC_AUTH_FILTER

BasicAuthenticationFilter

http/http-basic

SERVLET_API_SUPPORT_FILTER

SecurityContextHolderAwareRequestFilter

http/@servlet-api-provision

JAAS_API_SUPPORT_FILTER

JaasApiIntegrationFilter

http/@jaas-api-provision

REMEMBER_ME_FILTER

RememberMeAuthenticationFilter

http/remember-me

ANONYMOUS_FILTER

AnonymousAuthenticationFilter

http/anonymous

SESSION_MANAGEMENT_FILTER

SessionManagementFilter

session-management

EXCEPTION_TRANSLATION_FILTER

ExceptionTranslationFilter

http

FILTER_SECURITY_INTERCEPTOR

FilterSecurityInterceptor

http

SWITCH_USER_FILTER

SwitchUserFilter

不适用

您可以使用 custom-filter 元素和其中一个名称来指定过滤器在堆栈中出现的位置,从而将自己的过滤器添加到堆栈中

<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>

<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>

如果您希望将过滤器插入堆栈中另一个过滤器之前或之后,您也可以使用 afterbefore 属性。您可以将 FIRSTLASTposition 属性一起使用,分别表示您希望过滤器出现在整个堆栈之前或之后。

避免过滤器位置冲突

如果您插入的自定义过滤器可能与命名空间创建的标准过滤器之一占据相同的位置,您不应错误地包含命名空间版本。删除任何创建您要替换其功能的过滤器的元素。

请注意,您不能替换由 <http> 元素本身创建的过滤器:SecurityContextPersistenceFilterExceptionTranslationFilterFilterSecurityInterceptor。默认情况下,会添加一个 AnonymousAuthenticationFilter,除非您禁用了会话固定保护,否则还会将一个 SessionManagementFilter 添加到过滤器链中。

如果您替换需要认证入口点(即,认证过程由未经认证的用户尝试访问受保护资源触发)的命名空间过滤器,您还需要添加一个自定义入口点 bean。

方法安全

自 2.0 版本以来,Spring Security 对为服务层方法添加安全性提供了 substantial 支持。它支持 JSR-250 注解安全以及框架最初的 @Secured 注解。自 3.0 版本以来,您还可以使用基于表达式的注解。您可以将安全性应用于单个 bean(通过使用 intercept-methods 元素修饰 bean 声明),也可以使用 AspectJ 样式切入点来保护整个服务层中的多个 bean。

默认的 AccessDecisionManager

本节假设您对 Spring Security 中访问控制的底层架构有一些了解。如果您不了解,可以跳过本节稍后再返回,因为本节仅与需要进行一些自定义以使用更简单的基于角色的安全之外的人员相关。

当您使用命名空间配置时,会自动为您注册 AccessDecisionManager 的默认实例,并根据您在 intercept-urlprotect-pointcut 声明中(以及在注解中,如果您使用注解来保护方法)指定的访问属性,用于对方法调用和 Web URL 访问做出访问决策。

默认策略是使用带有 RoleVoterAuthenticatedVoterAffirmativeBased AccessDecisionManager。您可以在关于授权的章节中了解更多信息。

自定义 AccessDecisionManager

如果您需要使用更复杂的访问控制策略,可以为方法和 Web 安全设置替代方案。

对于方法安全,您可以通过将 global-method-security 上的 access-decision-manager-ref 属性设置为应用程序上下文中相应 AccessDecisionManager bean 的 id 来实现

<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>

Web 安全的语法相同,但属性位于 http 元素上

<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>
© . This site is unofficial and not affiliated with VMware.