Security Namespace Configuration
自 Spring Framework 的 2.0 版本以来,命名空间配置已经可用。它允许你使用来自其他 XML 模式的元素来补充传统 Spring Bean 应用程序上下文语法。你可以在 Spring Reference Documentation 中找到更多信息。你可以使用命名空间元素更简洁地配置单个 Bean,或者更强大地定义更紧密匹配问题域并向用户隐藏底层复杂性的替代配置语法。一个简单的元素可以隐藏这样的事实:多个 bean 和处理步骤正在添加到应用程序上下文中。例如,将 security
命名空间中的以下元素添加到应用程序上下文中,将启动一个嵌入式 LDAP 服务器,用于在应用程序中进行测试:
Namespace configuration has been available since version 2.0 of the Spring Framework.
It lets you supplement the traditional Spring beans application context syntax with elements from additional XML schema.
You can find more information in the Spring Reference Documentation.
You can use a namespace element to more concisely configure an individual bean or, more powerfully, to define an alternative configuration syntax that more closely matches the problem domain and hides the underlying complexity from the user.
A simple element can conceal the fact that multiple beans and processing steps are being added to the application context.
For example, adding the following element from the security
namespace to an application context starts up an embedded LDAP server for testing use within the application:
<security:ldap-server />
这比连接等效的 Apache Directory Server Bean 简单得多。最常见的替代配置要求由 ldap-server
元素上的属性支持,并且用户无需担心需要创建哪些 Bean 以及 Bean 属性名称是什么。可以在 LDAP Authentication 章节中找到有关使用 ldap-server
元素的更多信息。编辑应用程序上下文文件时,一个好的 XML 编辑器应提供有关可用属性和元素的信息。我们建议您尝试使用 Spring Tool Suite,因为它具有处理标准 Spring 命名空间的特殊功能。
This is much simpler than wiring up the equivalent Apache Directory Server beans.
The most common alternative configuration requirements are supported by attributes on the ldap-server
element, and the user is isolated from worrying about which beans they need to create and what the bean property names are.
You can find out more about the use of the ldap-server
element in the chapter on LDAP Authentication.
A good XML editor while editing the application context file should provide information on the attributes and elements that are available.
We recommend that you try the Spring Tool Suite, as it has special features for working with standard Spring namespaces.
要在应用程序上下文中开始使用 security
命名空间,请将 spring-security-config
jar 添加到您的类路径。然后,您只需将模式声明添加到您的应用程序上下文文件:
To start using the security
namespace in your application context, add the spring-security-config
jar to your classpath.
Then, all you need to do is add the schema declaration to your application context file:
<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
)用作默认命名空间,这意味着我们可以省略所有安全命名空间元素的前缀,从而使内容更易于阅读。如果您已将应用程序上下文分成不同的文件,并且将大部分安全配置都放在其中一个文件中,则您可能还想这样做。然后,您的安全应用程序上下文文件将由此开始:
In many of the examples you can see (and in the sample applications), we often use security
(rather than beans
) as the default namespace, which means we can omit the prefix on all the security namespace elements, making the content easier to read.
You may also want to do this if you have your application context divided up into separate files and have most of your security configuration in one of them.
Your security application context file would then start like this:
<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>
我们假设从此章节开始将使用此语法。
We assume this syntax is being used from now on in this chapter.
Design of the Namespace
命名空间旨在捕获框架中最常见的用法,并提供一个简化且简洁的语法,以便在应用程序中启用它们。设计基于框架内的更大规模依赖关系,可分为以下领域:
The namespace is designed to capture the most common uses of the framework and provide a simplified and concise syntax for enabling them within an application. The design is based around the large-scale dependencies within the framework and can be divided up into the following areas:
-
Web/HTTP Security is the most complex part. It sets up the filters and related service beans used to apply the framework authentication mechanisms, to secure URLs, render login and error pages, and much more.
-
Business Object (Method) Security defines options for securing the service layer.
-
AuthenticationManager handles authentication requests from other parts of the framework.
-
AccessDecisionManager provides access decisions for web and method security. A default one is registered, but you can choose to use a custom one, declared with normal Spring bean syntax.
-
AuthenticationProvider instances provide mechanisms against which the authentication manager authenticates users. The namespace provides supports for several standard options and a means of adding custom beans declared with a traditional syntax.
-
UserDetailsService is closely related to authentication providers but is often also required by other beans.
我们将在以下部分中了解如何配置这些领域。
We see how to configure these in the following sections.
Getting Started with Security Namespace Configuration
本节介绍如何构建命名空间配置,以使用框架的一些主要特性。我们假设您最初希望尽快启动并运行,并将身份验证支持和访问控制添加到现有 Web 应用程序,并进行一些测试登录。然后,我们来看看如何切换到对数据库或其他安全存储库进行身份验证。在后面的部分中,我们将介绍更高级的命名空间配置选项。
This section looks at how you can build up a namespace configuration to use some of the main features of the framework. We assume that you initially want to get up and running as quickly as possible and add authentication support and access control to an existing web application, with a few test logins. Then we look at how to change over to authenticating against a database or other security repository. In later sections, we introduce more advanced namespace configuration options.
web.xml Configuration
您需要做的第一件事是将以下过滤器声明添加到您的 web.xml
文件:
The first thing you need to do is add the following filter declaration to your web.xml
file:
<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
,它是由命名空间创建的用于处理 Web 安全的内部基础设施 bean。在本例中,bean 名称为“springSecurityFilterChain”,它是由命名空间创建的用于处理 Web 安全的内部基础设施 bean。请注意,您不应自己使用此 bean 名称。将此 bean 添加到 web.xml
后,即可开始编辑应用程序上下文文件。Web 安全服务由 <http>
元素配置。
DelegatingFilterProxy
is a Spring Framework class that delegates to a filter implementation that is defined as a Spring bean in your application context.
In this case, the bean is named springSecurityFilterChain
, which is an internal infrastructure bean created by the namespace to handle web security.
In this case, the bean is named "springSecurityFilterChain", which is an internal infrastructure bean created by the namespace to handle web security.
Note that you should not use this bean name yourself.
Once you have added this bean to your web.xml
, you are ready to start editing your application context file.
Web security services are configured by the <http>
element.
A Minimal <http> Configuration
要启用 Web 安全,您需要以下配置:
To enable web security, you need the following configuration:
<http>
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>
该列表说明我们希望:
That listing says that we want:
-
All URLs within our application to be secured, requiring the role
ROLE_USER
to access them -
To log in to the application using a form with username and password
-
A logout URL registered which will allow us to log out of the application
<http>
元素是所有与 Web 相关的命名空间功能的父类。<intercept-url>
元素定义了一个 pattern
,它使用 Ant 路径语法与传入请求的 URL 匹配。有关实际执行匹配的更多详细信息,请参阅有关 HttpFirewall
的部分。您还可以使用正则表达式匹配作为替代方案(有关更多详细信息,请参阅命名空间附录)。access
属性定义与给定模式匹配的请求的访问要求。在默认配置中,这通常是逗号分隔的角色列表,用户必须具有其中一个角色才能获得发出请求的权限。ROLE_
前缀是一个标记,指示应该与用户的权限进行简单比较。换句话说,应该使用基于正常角色的检查。Spring Security 中的访问控制不仅仅限于使用简单角色(因此使用前缀来区分不同类型的安全属性)。我们稍后会看到解释如何变化。access
属性中逗号分隔值的解释取决于使用 <<`AccessDecisionManager`,ns-access-manager>> 的实现。自 Spring Security 3.0 以来,您还可以填充 EL expression 的属性。
The <http>
element is the parent for all web-related namespace functionality.
The <intercept-url>
element defines a pattern
, which is matched against the URLs of incoming requests using Ant path syntax. See the section on HttpFirewall
for more details on how matches are actually performed.
You can also use regular-expression matching as an alternative (see the namespace appendix for more details).
The access
attribute defines the access requirements for requests that match the given pattern.
With the default configuration, this is typically a comma-separated list of roles, one of which a user must have to be allowed to make the request.
The ROLE_
prefix is a marker that indicates that a simple comparison with the user’s authorities should be made.
In other words, a normal role-based check should be used.
Access-control in Spring Security is not limited to the use of simple roles (hence the use of the prefix to differentiate between different types of security attributes).
We see later how the interpretation can vary. The interpretation of the comma-separated values in the access
attribute depends on the which implementation of the <<`AccessDecisionManager`,ns-access-manager>> is used.
Since Spring Security 3.0, you can also populate the attribute with an EL expression.
您可以使用多个 You can use multiple |
要添加用户,您可以在命名空间中直接定义一组测试数据:
To add users, you can define a set of test data directly in the namespace:
<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 进行哈希:
The preceding listing shows an example of a secure way to store the same passwords.
The password is prefixed with {bcrypt}
to instruct DelegatingPasswordEncoder
, which supports any configured PasswordEncoder
for matching, that the passwords are hashed using 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>
元素负责创建 FilterChainProxy
及其使用的过滤器 bean。先前的常见问题,例如过滤器排序不正确,现在不再是问题,因为过滤器位置是预定义的。
The <http>
element is responsible for creating a FilterChainProxy
and the filter beans that it uses.
Previously common problems, such as incorrect filter ordering, are no longer an issue, as the filter positions are predefined.
<authentication-provider>
元素创建一个 DaoAuthenticationProvider
Bean,<user-service>
元素创建一个 InMemoryDaoImpl
。所有 authentication-provider
元素都必须是 <authentication-manager>
元素的子元素,该元素创建一个 ProviderManager
并向其中注册身份验证提供程序。您可以在 namespace appendix 中找到有关所创建 Bean 的更详细信息。如果您想开始了解框架中的重要类以及如何使用它们,尤其是在您稍后想要定制内容时,应仔细检查此附录。
The <authentication-provider>
element creates a DaoAuthenticationProvider
bean, and the <user-service>
element creates an InMemoryDaoImpl
.
All authentication-provider
elements must be children of the <authentication-manager>
element, which creates a ProviderManager
and registers the authentication providers with it.
You can find more detailed information on the beans that are created in the namespace appendix.
You should cross-check this appendix if you want to start understanding what the important classes in the framework are and how they are used, particularly if you want to customize things later.
前面的配置定义了两个用户及其密码和在应用程序中的角色(用于访问控制)。您还可以通过设置 user-service
元素上的 properties
属性从标准属性文件加载用户信息。有关文件格式的更多详细信息,请参阅有关 in-memory authentication 的部分。使用 <authentication-provider>
元素意味着用户信息将被身份验证管理器用于处理身份验证请求。您可以使用多个 <authentication-provider>
元素来定义不同的身份验证来源。每次咨询一个。
The preceding configuration defines two users, their passwords, and their roles within the application (which are used for access control).
You can also possible load user information from a standard properties file by setting the properties
attribute on the user-service
element.
See the section on in-memory authentication for more details on the file format.
Using the <authentication-provider>
element means that the user information is used by the authentication manager to process authentication requests.
You can have multiple <authentication-provider>
elements to define different authentication sources. Each is consulted in turn.
在此时,您应该能够启动您的应用程序,并且您应该需要进行登录才能继续。试一试,或者尝试使用该项目附带的 “tutorial” 示例应用程序进行实验。
At this point, you should be able to start up your application, and you should be required to log in to proceed. Try it out, or try experimenting with the “tutorial” sample application that comes with the project.
Setting a Default Post-Login Destination
如果尝试访问受保护资源未提示使用表单登录,那么 “default-target-url” 选项就会发挥作用。这是用户成功登录后被带到的 URL。它默认为 “/”。您还可以配置一切,以便用户始终最终到达此页面(无论登录是 “按需” 还是他们明确选择登录),方法是将 “always-use-default-target” 属性设置为 “true”。比如,如果您的应用程序始终要求用户从 “主页” 开始,这样做就非常有用:
If a form login is not prompted by an attempt to access a protected resource, the default-target-url
option comes into play.
This is the URL to which the user is taken after successfully logging in. it defaults to /
.
You can also configure things so that the user always ends up at this page (regardless of whether the login was “on-demand” or they explicitly chose to log in) by setting the always-use-default-target
attribute to true
.
This is useful if your application always requires that the user starts at a “home” page, for example:
<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” 实例。
For even more control over the destination, you can use the authentication-success-handler-ref
attribute as an alternative to default-target-url
.
The referenced bean should be an instance of AuthenticationSuccessHandler
.
Advanced Web Features
本节将介绍超出基本内容的各种功能。
This section covers various features that go beyond the basics.
Adding in Your Own Filters
如果您之前用过 Spring Security,您就会知道该框架维护着它用来应用其服务的过滤器链。您可能希望在特定位置向堆栈中添加您自己的过滤器,或使用当前没有名称空间配置选项的 Spring Security 过滤器(例如 CAS)。或者,您可能希望使用已自定义的标准名称空间过滤器版本,比如通过 <form-login>
元素创建的 “UsernamePasswordAuthenticationFilter” ,以利用显式使用该 bean 时可用的某些额外配置选项。因为过滤器链并没有直接公开,您如何使用名称空间配置来完成这项操作?
If you have used Spring Security before, you know that the framework maintains a chain of filters that it uses to apply its services.
You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there is not currently a namespace configuration option (CAS, for example).
Alternatively, you might want to use a customized version of a standard namespace filter, such as the UsernamePasswordAuthenticationFilter
(which is created by the <form-login>
element) to take advantage of some of the extra configuration options that are available when you use the bean explicitly.
How can you do this with namespace configuration, since the filter chain is not directly exposed?
当您使用名称空间时,始终严格执行过滤器的顺序。在创建应用程序上下文时,过滤器 bean 由名称空间处理代码进行排序,并且标准 Spring Security 过滤器在名称空间中都有别名和众所周知的位置。
The order of the filters is always strictly enforced when you use the namespace. When the application context is being created, the filter beans are sorted by the namespace handling code, and the standard Spring Security filters each have an alias in the namespace and a well-known position.
在之前的版本中,排序在创建了过滤器实例之后进行,在对应用程序上下文进行后处理期间。在 3.0+ 版中,排序现在在 bean 元数据级别进行,在实例化类之前。这对您如何向堆栈中添加自己的过滤器产生影响,因为在解析 In previous versions, the sorting took place after the filter instances had been created, during post-processing of the application context.
In version 3.0+ the sorting is now done at the bean metadata level, before the classes have been instantiated.
This has implications for how you add your own filters to the stack as the entire filter list must be known during the parsing of the |
过滤器、别名和创建过滤器的名称空间元素和属性显示在以下表格中,按它们在过滤器链中出现的顺序:
The filters, aliases, and namespace elements and attributes that create the filters are shown in the following table, in the order in which they occur in the filter chain:
Alias | Filter Class | Namespace Element or Attribute |
---|---|---|
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” 元素和其中一个名称向堆栈中添加您自己的过滤器,以指定您的过滤器应该出现的为止:
You can add your own filter to the stack by using the custom-filter
element and one of these names to specify the position at which your filter should appear:
<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>
<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>
如果您希望在堆栈中另一过滤器之前或之后插入您的过滤器,您还可以使用 “after” 或 “before” 属性。您可以将 “FIRST” 和 “LAST” 与 “position” 属性一起使用,以指示希望您的过滤器分别位于整个堆栈之前或之后。
You can also use the after
or before
attributes if you want your filter to be inserted before or after another filter in the stack.
You can use FIRST
and LAST
with the position
attribute to indicate that you want your filter to appear before or after the entire stack, respectively.
Avoiding filter position conflicts
如果您插入了可能占据与该名称空间创建的某个标准过滤器相同位置的自定义过滤器,您就不应该错误地包括名称空间版本。删除创建了您希望替换其功能的过滤器的任何元素。 If you insert a custom filter that may occupy the same position as one of the standard filters created by the namespace, you should not include the namespace versions by mistake. Remove any elements that create filters whose functionality you want to replace. 请注意,您无法替换由使用 Note that you cannot replace filters that are created by the use of the |
如果您替换了需要某个身份验证入口点(即,身份验证过程是由未经身份验证的用户试图访问安全资源触发的)的名称空间过滤器,您还需要添加一个自定义入口点 bean。
If you replace a namespace filter that requires an authentication entry point (that is, where the authentication process is triggered by an unauthenticated user’s attempt to access to a secured resource), you need to add a custom entry-point bean too.
Method Security
自 2.0 版本以来,Spring Security 为向服务层方法中添加安全性提供了大量的支持。它提供了对 JSR-250 注释安全的支持,以及该框架的原始 @Secured
注释。自 3.0 版本以来,您还可以使用 expression-based annotations。您可以通过使用 intercept-methods
元素装饰 Bean 声明将安全性应用到单个 Bean,或者可以使用 AspectJ 样式切入点保护整个服务层中的多个 Bean。
Since version 2.0, Spring Security has substantial support for adding security to your service layer methods.
It provides support for JSR-250 annotation security as well as the framework’s original @Secured
annotation.
Since version 3.0, you can also make use of expression-based annotations.
You can apply security to a single bean (by using the intercept-methods
element to decorate the bean declaration), or you can secure multiple beans across the entire service layer using the AspectJ style pointcuts.
The Default AccessDecisionManager
本节假定您对 Spring Security 内访问控制中底层架构具有一定了解。如果没有,您可以跳过它并稍后再回头阅读,因为本节仅与需要进行一些自定义以使用不仅仅是基于角色的安全的人员相关。
This section assumes that you have some knowledge of the underlying architecture for access-control within Spring Security. If you do not, you can skip it and come back to it later, as this section is relevant only for people who need to do some customization to use more than simple role-based security.
当您使用名称空间配置时,会自动为您注册 “AccessDecisionManager” 的默认实例,并且使用它根据您在 “intercept-url” 和 “protect-pointcut” 声明中指定的访问属性(以及如果您使用注释保护方法,在注释中)对方法调用和 Web URL 访问做出访问决策。
When you use a namespace configuration, a default instance of AccessDecisionManager
is automatically registered for you and is used to make access decisions for method invocations and web URL access, based on the access attributes you specify in your intercept-url
and protect-pointcut
declarations (and in annotations, if you use annotations to secure methods).
默认策略是使用带有 RoleVoter
和 AuthenticatedVoter
的 AffirmativeBased
AccessDecisionManager
。您可以在 authorization 一章中找到有关它们的更多信息。
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 authorization.
Customizing the AccessDecisionManager
如果您需要使用更复杂的访问控制策略,您可以为方法和 Web 安全同时设置一个备用策略。
If you need to use a more complicated access control strategy, you can set an alternative for both method and web security.
对于方法安全,您可以通过在 “global-method-security” 上将 “access-decision-manager-ref” 属性设置为应用程序上下文中适当 “AccessDecisionManager” bean 的 “id” 来执行此操作:
For method security, you do so by setting the access-decision-manager-ref
attribute on global-method-security
to the id
of the appropriate AccessDecisionManager
bean in the application context:
<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>
Web 安全的语法相同,但该属性位于 “http” 元素上:
The syntax for web security is the same, but the attribute is on the http
element:
<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>