Spring Security(一):官网向导翻译

原文出自  https://spring.io/guides/topicals/spring-security-architecture

Spring Security Architecture

     This guide is a primer for Spring Security, offering insight into the design and basic building blocks of the framework. We only cover the very basics of application security but in doing so we can clear up some of the confusion experienced by developers using Spring Security. To do this we take a look at the way security is applied in web applications using filters and more generally using method annotations. Use this guide when you need to understand at a high level how a secure application works, and how it can be customized, or if you just need to learn how to think about application security.
 
   本指南是Spring Security的入门读物,提供对框架设计和基本构建块的深入了解。我们只介绍应用程序安全性的基础知识,但这样做可以清除开发人员使用Spring Security时遇到的一些困惑。为此,我们将介绍使用过滤器在Web应用程序中应用安全性的方式更常见的是使用方法注释。当您需要从高层次了解安全应用程序如何工作,如何自定义,或者您只需要学习如何考虑应用程序安全性时,请使用本指南。
 
     This guide is not intended as a manual or recipe for solving more than the most basic problems (there are other sources for those), but it could be useful for beginners and experts alike. Spring Boot is also referred to a lot because it provides some default behaviour for a secure application and it can be useful to understand how that fits in with the overall architecture. All of the principles apply equally well to applications that do not use Spring Boot.
 
       本指南不是作为解决超过最基本问题的手册或配方(还有其他来源),但它对初学者和专家都很有用。 Spring Boot也引用了很多,因为它为安全应用程序提供了一些默认行为,了解它如何适应整体架构非常有用。所有原则同样适用于不使用Spring Boot的应用程序。
 

Authentication and Access Control

       Application security boils down to two more or less independent problems: authentication (who are you?) and authorization (what are you allowed to do?). Sometimes people say "access control" instead of "authorization" which can get confusing, but it can be helpful to think of it that way because "authorization" is overloaded in other places. Spring Security has an architecture that is designed to separate authentication from authorization, and has strategies and extension points for both.  

     应用程序安全性可归结为两个或多或少独立的问题:身份验证(您是谁?)和授权(您可以做什么?)。有时候人们会说“访问控制”而不是“授权”,这会让人感到困惑,但是因为“授权”在其他地方过载会有所帮助。 Spring Security的架构旨在将身份验证与授权分开,并为两者提供策略和扩展点。

  Authentication

The main strategy interface for authentication is AuthenticationManager which only has one method:

 身份验证的主要策略接口是 AuthenticationManager ,它只有一个方法:

public interface AuthenticationManager {
  Authentication authenticate(Authentication authentication)
    throws AuthenticationException;
}

 An AuthenticationManager can do one of 3 things in its authenticate()method:

AuthenticationManager可以在authenticate()方法中执行以下三种操作之一:

1、return an Authentication (normally with authenticated=true) if it can verify that the input represents a valid principal.

1、如果它可以验证输入是否代表有效的主体,则返回身份验证(通常使用authenticated = true)。

 
2、throw an AuthenticationException if it believes that the input represents an invalid principal.
2、如果它认为输入表示无效的主体,则抛出AuthenticationException。
 
3、return  null  if it can’t decide.
3、如果无法决定,则返回null。
 
AuthenticationException is a runtime exception. It is usually handled by an application in a generic way, depending on the style or purpose of the application. In other words user code is not normally expected to catch and handle it. For example, a web UI will render a page that says that the authentication failed, and a backend HTTP service will send a 401 response, with or without a WWW-Authenticate header depending on the context.
 
AuthenticationException是运行时异常。它通常由应用程序以通用方式处理,具体取决于应用程序的样式或目的。换句话说,通常不希望用户代码捕获并处理它。例如,Web UI将呈现一个页面,表明身份验证失败,后端HTTP服务将发送401响应,具有或不具有WWW-Authenticate标头,具体取决于上下文。
 
The most commonly used implementation of AuthenticationManager is ProviderManager, which delegates to a chain of AuthenticationProvider instances. An AuthenticationProvider is a bit like an AuthenticationManager but it has an extra method to allow the caller to query if it supports a given Authentication type:
 
AuthenticationManager最常用的实现是ProviderManager,它委托一系列AuthenticationProvider实例。 AuthenticationProvider有点像AuthenticationManager,但它有一个额外的方法允许调用者查询它是否支持给定的身份验证类型:
 
public interface AuthenticationProvider {

	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;

	boolean supports(Class<?> authentication);

}

 

The Class<?> argument in the supports() method is really Class<? extends Authentication> (it will only ever be asked if it supports something that will be passed into the authenticate() method). A ProviderManager can support multiple different authentication mechanisms in the same application by delegating to a chain of AuthenticationProviders. If a ProviderManager doesn’t recognise a particular Authentication instance type it will be skipped.

supports()方法中的Class <?>参数实际上是Class <?扩展身份验证>(只会询问它是否支持将传递给authenticate()方法的内容)。通过委派给AuthenticationProviders链,ProviderManager可以在同一个应用程序中支持多种不同的身份验证机制。如果ProviderManager无法识别特定的身份验证实例类型,则会跳过它。

ProviderManager has an optional parent, which it can consult if all providers return null. If the parent is not available then a null Authentication results in an AuthenticationException.

ProviderManager有一个可选的父级,如果所有提供者都返回null,它可以查询。如果父级不可用,则null验证会导致AuthenticationException。
 

Sometimes an application has logical groups of protected resources (e.g. all web resources that match a path pattern /api/**), and each group can have its own dedicated AuthenticationManager. Often, each of those is a ProviderManager, and they share a parent. The parent is then a kind of "global" resource, acting as a fallback for all providers.

有时,应用程序具有受保护资源的逻辑组(例如,与路径模式/ api / **匹配的所有Web资源),并且每个组可以具有其自己的专用AuthenticationManager。通常,每个都是ProviderManager,并且它们共享父级。然后,父母就是一种“全球”资源,充当所有提供者的后备资源。
 
 

Figure 1. An AuthenticationManager hierarchy using ProviderManager

图1.使用ProviderManager的AuthenticationManager层次结构
 

Customizing Authentication Managers(自定义身份验证管理器)

Spring Security provides some configuration helpers to quickly get common authentication manager features set up in your application. The most commonly used helper is the AuthenticationManagerBuilder which is great for setting up in-memory, JDBC or LDAP user details, or for adding a custom UserDetailsService. Here’s an example of an application configuring the global (parent) 

Spring Security提供了一些配置帮助程序,可以快速获取应用程序中设置的常见身份验证管理器功能。最常用的帮助程序是AuthenticationManagerBuilder它非常适合设置内存,JDBC或LDAP用户详细信息,或者用于添加自定义UserDetailsS​​ervice。这是配置全局(父)的应用程序的示例
 
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

   ... // web stuff here

  @Autowired
  public initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
    builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
      .password("secret").roles("USER");
  }

}

  

This example relates to a web application, but the usage of AuthenticationManagerBuilder is more widely applicable (see below for more detail on how web application security is implemented). Note that the AuthenticationManagerBuilder is @Autowired into a method in a @Bean - that is what makes it build the global (parent) AuthenticationManager. In contrast if we had done it this way:

此示例涉及Web应用程序,但AuthenticationManagerBuilder的使用范围更广泛(有关如何实现Web应用程序安全性的更多详细信息,请参阅下文)。请注意,AuthenticationManagerBuilder是@Autowired到@Bean中的方法 - 这使得它构建全局(父)AuthenticationManager。相反,如果我们这样做:
 
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

  @Autowired
  DataSource dataSource;

   ... // web stuff here

  @Override
  public configure(AuthenticationManagerBuilder builder) {
    builder.jdbcAuthentication().dataSource(dataSource).withUser("dave")
      .password("secret").roles("USER");
  }

}

(using an @Override of a method in the configurer) then the AuthenticationManagerBuilder is only used to build a "local" AuthenticationManager, which is a child of the global one. In a Spring Boot application you can @Autowired the global one into another bean, but you can’t do that with the local one unless you explicitly expose it yourself.

(使用配置程序中的方法的@Override),然后AuthenticationManagerBuilder仅用于构建“本地”AuthenticationManager,它是全局的AuthenticationManager的孩子。在Spring Boot应用程序中,你可以@Autowired全局的bean到另一个bean,但除非你自己明确地公开它,否则你不能用本地bean。
 
Spring Boot provides a default global AuthenticationManager (with just one user) unless you pre-empt it by providing your own bean of type AuthenticationManager. The default is secure enough on its own for you not to have to worry about it much, unless you actively need a custom global AuthenticationManager. If you do any configuration that builds an AuthenticationManager you can often do it locally to the resources that you are protecting and not worry about the global default.
 
Spring Boot提供了一个默认的全局AuthenticationManager(只有一个用户),除非您通过提供自己的AuthenticationManager类型的bean来抢占它。除非您主动需要自定义全局AuthenticationManager,否则默认设置足够安全,您不必担心它。如果您执行构建AuthenticationManager的任何配置,您通常可以在本地执行您正在保护的资源,而不必担心全局默认值。
 

Authorization or Access Control(授权或访问控制)

Once authentication is successful, we can move on to authorization, and the core strategy here is AccessDecisionManager. There are three implementations provided by the framework and all three delegate to a chain of AccessDecisionVoter, a bit like the ProviderManager delegates to AuthenticationProviders.

一旦身份验证成功,我们就可以继续授权,这里的核心策略是AccessDecisionManager。框架提供了三种实现,并且三者都委托给AccessDecisionVoter链,有点像ProviderManager委托给AuthenticationProviders。
 
An AccessDecisionVoter considers an Authentication (representing a principal) and a secure Object which as been decorated with ConfigAttributes:
 
AccessDecisionVoter考虑使用ConfigAttributes修饰的身份验证(表示主体)和安全对象:
 
boolean supports(ConfigAttribute attribute);

boolean supports(Class<?> clazz);

int vote(Authentication authentication, S object,
        Collection<ConfigAttribute> attributes);

The Object is completely generic in the signatures of the AccessDecisionManager and AccessDecisionVoter - it represents anything that a user might want to access (a web resource or a method in a Java class are the two most common cases). The ConfigAttributes are also fairly generic, representing a decoration of the secure Object with some metadata that determine the level of permission required to access it. ConfigAttribute is an interface but it only has one method which is quite generic and returns a String, so these strings encode in some way the intention of the owner of the resource, expressing rules about who is allowed to access it. A typical ConfigAttribute is the name of a user role (like ROLE_ADMIN or ROLE_AUDIT), and they often have special formats (like the ROLE_ prefix) or represent expressions that need to be evaluated.

Object在AccessDecisionManager和AccessDecisionVoter的签名中是完全通用的 - 它表示用户可能想要访问的任何内容(Web资源或Java类中的方法是两种最常见的情况)。 ConfigAttributes也非常通用,表示安全对象的装饰,其中包含一些元数据,用于确定访问它所需的权限级别。 ConfigAttribute是一个接口,但它只有一个非常通用的方法并返回一个String,因此这些字符串以某种方式编码资源所有者的意图,表达允许谁访问它的规则。典型的ConfigAttribute是用户角色的名称(如ROLE_ADMIN或ROLE_AUDIT),它们通常具有特殊格式(如ROLE_前缀)或表示需要评估的表达式。
 
Most people just use the default AccessDecisionManager which is AffirmativeBased (if no voters decline then access is granted). Any customization tends to happen in the voters, either adding new ones, or modifying the way that the existing ones work.
 
大多数人只使用AffirmativeBased的默认AccessDecisionManager(如果没有选民拒绝,则授予访问权限)。任何定制都倾向于在选民中发生,要么添加新的定制,要么修改现有定制的方式。
 
It is very common to use ConfigAttributes that are Spring Expression Language (SpEL) expressions, for example isFullyAuthenticated() && hasRole('FOO'). This is supported by an AccessDecisionVoter that can handle the expressions and create a context for them. To extend the range of expressions that can be handled requires a custom implementation of SecurityExpressionRoot and sometimes also SecurityExpressionHandler.
 
使用Spring表达式语言(SpEL)表达式的ConfigAttributes是很常见的,例如isFullyAuthenticated()&& hasRole('FOO')。这是由AccessDecisionVoter支持的,它可以处理表达式并为它们创建上下文。要扩展可处理的表达式范围,需要使用SecurityExpressionRoot的自定义实现,有时还需要SecurityExpressionHandler。
 

Web Security(网络安全)

Spring Security in the web tier (for UIs and HTTP back ends) is based on Servlet Filters, so it is helpful to look at the role of Filters generally first. The picture below shows the typical layering of the handlers for a single HTTP request.

Web层中的Spring Security(用于UI和HTTP后端)基于Servlet过滤器,因此通常首先查看过滤器的作用是有帮助的。下图显示了单个HTTP请求的处理程序的典型分层。
 

 

The client sends a request to the app, and the container decides which filters and which servlet apply to it based on the path of the request URI. At most one servlet can handle a single request, but filters form a chain, so they are ordered, and in fact a filter can veto the rest of the chain if it wants to handle the request itself. A filter can also modify the request and/or the response used in the downstream filters and servlet. The order of the filter chain is very important, and Spring Boot manages it through 2 mechanisms: one is that @Beans of type Filter can have an @Order or implement Ordered, and the other is that they can be part of a FilterRegistrationBean that itself has an order as part of its API. Some off-the-shelf filters define their own constants to help signal what order they like to be in relative to each other (e.g. the SessionRepositoryFilter from Spring Session has a DEFAULT_ORDER of Integer.MIN_VALUE + 50, which tells us it likes to be early in the chain, but it doesn’t rule out other filters coming before it).

客户端向应用程序发送请求,容器根据请求URI的路径决定哪些过滤器和哪个servlet应用于它。最多一个servlet可以处理单个请求,但是过滤器形成一个链,因此它们是有序的,实际上,如果过滤器想要处理请求本身,则可以否决链的其余部分。过滤器还可以修改下游过滤器和servlet中使用的请求和/或响应。过滤器链的顺序非常重要,Spring Boot通过两种机制对其进行管理:一种是类型为Filter的@Beans可以有一个@Order或者实现Ordered,另一种是它们可以成为FilterRegistrationBean的一部分。订单作为其API的一部分。一些现成的过滤器定义了它们自己的常量,以帮助表明它们相对于彼此的顺序(例如,来自Spring Session的SessionRepositoryFilter的DEFAULT_ORDER为Integer.MIN_VALUE + 50,这告诉我们它喜欢早在链中,但它不排除其前的其他过滤器)。
 
Spring Security is installed as a single Filter in the chain, and its concerete type is FilterChainProxy, for reasons that will become apparent soon. In a Spring Boot app the security filter is a @Bean in the ApplicationContext, and it is installed by default so that it is applied to every request. It is installed at a position defined by SecurityProperties.DEFAULT_FILTER_ORDER, which in turn is anchored by FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER (the maximum order that a Spring Boot app expects filters to have if they wrap the request, modifying its behaviour). There’s more to it than that though: from the point of view of the container Spring Security is a single filter, but inside it there are additional filters, each playing a special role. Here’s a picture:
 
Spring Security作为链中的单个Filter安装,其concerete类型是FilterChainProxy,原因很快就会显现出来。在Spring Boot应用程序中,security filter是ApplicationContext中的@Bean,默认情况下会安装它,以便将其应用于每个请求。它安装在SecurityProperties.DEFAULT_FILTER_ORDER定义的位置,而该位置又由FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER锚定(Spring Boot应用程序期望过滤器在包装请求时修改其行为的最大顺序)。除此之外还有更多:从容器的角度来看,Spring Security是一个单独的过滤器,但在其中有一些额外的过滤器,每个过滤器都扮演着特殊的角色。这是一张图片:
 

 

Figure 2. Spring Security is a single physical Filter but delegates processing to a chain of internal filters

图2. Spring Security是一个单独的物理过滤器,但将处理委托给一系列内部过滤器
 
In fact there is even one more layer of indirection in the security filter: it is usually installed in the container as a DelegatingFilterProxy, which does not have to be a Spring @Bean. The proxy delegates to a FilterChainProxy which is always a @Bean, usually with a fixed name of springSecurityFilterChain. It is the FilterChainProxy which contains all the security logic arranged internally as a chain (or chains) of filters. All the filters have the same API (they all implement the Filter interface from the Servlet Spec) and they all have the opportunity to veto the rest of the chain.
 
事实上,安全过滤器中甚至还有一层间接:它通常作为DelegatingFilterProxy安装在容器中,它不必是Spring @Bean。代理委托给FilterChainProxy,它始终是@Bean,通常具有固定名称springSecurityFilterChain。它是FilterChainProxy,它包含内部排列为过滤器链(或链)的所有安全逻辑。所有过滤器都具有相同的API(它们都实现了Servlet规范中的Filter接口),并且它们都有机会否决链的其余部分。
 
There can be multiple filter chains all managed by Spring Security in the same top level FilterChainProxy and all unknown to the container. The Spring Security filter contains a list of filter chains, and dispatches a request to the first chain that matches it. The picture below shows the dispatch happening based on matching the request path (/foo/** matches before /**). This is very common but not the only way to match a request. The most important feature of this dispatch process is that only one chain ever handles a request.
 
可以有多个过滤器链,所有过滤器链都由Spring Security在同一顶级FilterChainProxy中管理,并且容器都是未知的。 Spring Security过滤器包含过滤器链列表,并将请求分派给与其匹配的第一个链。下图显示了基于匹配请求路径(/ foo / **匹配在/ **之前)发生的调度。这很常见,但不是匹配请求的唯一方法。此调度过程的最重要特征是只有一个链处理请求。
 

Figure 3. The Spring Security FilterChainProxy dispatches requests to the first chain that matches.

图3. Spring Security FilterChainProxy将请求分派给匹配的第一个链。
 
A vanilla Spring Boot application with no custom security configuration has a several (call it n) filter chains, where usually n=6. The first (n-1) chains are there just to ignore static resource patterns, like /css/** and /images/**, and the error view /error (the paths can be controlled by the user with security.ignored from the SecurityProperties configuration bean). The last chain matches the catch all path /** and is more active, containing logic for authentication, authorization, exception handling, session handling, header writing, etc. There are a total of 11 filters in this chain by default, but normally it is not necessary for users to concern themselves with which filters are used and when.
 
没有自定义安全配置的vanilla Spring Boot应用程序有几个(称为n)过滤器链,通常n = 6。第一个(n-1)链只是为了忽略静态资源模式,比如/ css / **和/ images / **,以及错误视图 /error(路径可以由具有security.ignored的用户控制) SecurityProperties配置bean)。最后一个链匹配catch all path / **并且更活跃,包含用于身份验证,授权,异常处理,会话处理,标题写入等的逻辑。默认情况下,此链中总共有11个过滤器,但通常它用户不必关心使用哪些过滤器以及何时使用过滤器。
 
Note:
The fact that all filters internal to Spring Security are unknown to the container is important, especially in a Spring Boot application, where all @Beans of type Filter are registered automatically with the container by default. So if you want to add a custom filter to the security chain, you need to either not make it a @Bean or wrap it in a FilterRegistrationBean that explicitly disables the container registration.

注意 Spring安全内部的所有过滤器都不为容器所知,这一点很重要,尤其是在Spring Boot应用程序中,默认情况下,所有类型为Filter的@Beans都会自动注册到容器中。因此,如果要向安全链添加自定义筛选器,则需要将其设置为@Bean或将其包装在显式禁用容器注册的FilterRegistrationBean中。

Creating and Customizing Filter Chains(创建和自定义筛选链)

The default fallback filter chain in a Spring Boot app (the one with the /**request matcher) has a predefined order of SecurityProperties.BASIC_AUTH_ORDER. You can switch it off completely by setting security.basic.enabled=false, or you can use it as a fallback and just define other rules with a lower order. To do that just add a @Bean of type WebSecurityConfigurerAdapter (or WebSecurityConfigurer) and decorate the class with @Order. Example:

Spring Boot应用程序(具有/ **请求匹配器的应用程序)中的默认回退过滤器链具有SecurityProperties.BASIC_AUTH_ORDER的预定义顺序。您可以通过设置security.basic.enabled = false将其完全关闭,或者您可以将其用作后备并仅使用较低的顺序定义其他规则。为此,只需添加一个类型为WebSecurityConfigurerAdapter(或WebSecurityConfigurer)的@Bean,并使用@Order修饰该类。例:
 
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
     ...;
  }
}

This bean will cause Spring Security to add a new filter chain and order it before the fallback.

此bean将导致Spring Security添加新的过滤器链并在回退之前对其进行排序。
 
Many applications have completely different access rules for one set of resources compared to another. For example an application that hosts a UI and a backing API might support cookie-based authentication with a redirect to a login page for the UI parts, and token-based authentication with a 401 response to unauthenticated requests for the API parts. Each set of resources has its own WebSecurityConfigurerAdapter with a unique order and a its own request matcher. If the matching rules overlap the earliest ordered filter chain will win.
 
与另一组资源相比,许多应用程序对一组资源具有完全不同的访问规则。例如,承载UI和支持API的应用程序可能支持基于cookie的身份验证,其中重定向到UI部件的登录页面,以及基于令牌的身份验证,其中401响应未经身份验证的API部件请求。每组资源都有自己的WebSecurityConfigurerAdapter,它具有唯一的顺序和自己的请求匹配器。如果匹配规则重叠,最早的有序过滤器链将获胜。
 

Request Matching for Dispatch and Authorization(请求匹配调度和授权)

A security filter chain (or equivalently a WebSecurityConfigurerAdapter) has a request matcher that is used for deciding whether to apply it to an HTTP request. Once the decision is made to apply a particular filter chain, no others are applied. But within a filter chain you can have more fine grained control of authorization by setting additional matchers in the HttpSecurity configurer. Example:

安全过滤器链(或等效的WebSecurityConfigurerAdapter)具有请求匹配器,用于决定是否将其应用于HTTP请求。一旦决定应用特定过滤器链,则不应用其他过滤器链。但是在过滤器链中,您可以通过在HttpSecurity配置器中设置其他匹配器来对授权进行更精细的控制。例:
 
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")  【整个过滤器链的请求匹配器】
      .authorizeRequests()
        .antMatchers("/foo/bar").hasRole("BAR")    【要应用的访问规则】
        .antMatchers("/foo/spam").hasRole("SPAM")
        .anyRequest().isAuthenticated();
  }
}

One of the easiest mistakes to make with configuring Spring Security is to forget that these matchers apply to different processes, one is a request matcher for the whole filter chain, and the other is only to choose the access rule to apply.

配置Spring Security最容易犯的错误之一就是忘记这些匹配器适用于不同的进程,一个是整个过滤器链的请求匹配器,另一个是选择要应用的访问规则。
 

Combining Application Security Rules with Actuator Rules(将应用程序安全规则与Actuator规则相结合)

If you are using the Spring Boot Actuator for management endpoints, you probably want them to be secure, and by default they will be. In fact as soon as you add the Actuator to a secure application you get an additional filter chain that applies only to the actuator endpoints. It is defined with a request matcher that matches only actuator endpoints and it has an order of ManagementServerProperties.BASIC_AUTH_ORDER which is 5 fewer than the default SecurityProperties fallback filter, so it is consulted before the fallback.

如果您将Spring Boot Actuator用于管理端点,您可能希望它们是安全的,并且默认情况下它们将是安全的。实际上,只要将Actuator添加到安全应用程序中,您就会获得一个仅适用于 Actuator 端点的附加过滤器链。它由一个仅匹配 Actuator 端点的请求匹配器定义,并且它具有ManagementServerProperties.BASIC_AUTH_ORDER的顺序,它比默认的SecurityProperties回退过滤器少5,因此在回退之前会查询它。
 
If you want your application security rules to apply to the actuator endpoints you can add a filter chain ordered earlier than the actuator one and with a request matcher that includes all actuator endpoints. If you prefer the default security settings for the actuator endpoints, then the easiest thing is to add your own filter later than the actuator one, but earlier than the fallback (e.g. ManagementServerProperties.BASIC_AUTH_ORDER + 1). Example:
 
如果您希望将应用程序安全规则应用于 actuator 端点,则可以添加比 actuator 端点更早排序的过滤器链以及包含所有 actuator 端点的请求匹配器。如果您更喜欢 actuator 端点的默认安全设置,那么最简单的方法是在 actuator 之后添加自己的过滤器,但要比回退更早(例如ManagementServerProperties.BASIC_AUTH_ORDER + 1)。例:
 
@Configuration
@Order(ManagementServerProperties.BASIC_AUTH_ORDER + 1)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/foo/**")
     ...;
  }
}
Note
Spring Security in the web tier is currently tied to the Servlet API, so it is only really applicable when running an app in a servlet container, either embedded or otherwise. It is not, however, tied to Spring MVC or the rest of the Spring web stack, so it can be used in any servlet application, for instance one using JAX-RS.

注意 Web层中的Spring Security目前与Servlet API相关联,因此它只适用于在嵌入式或其他方式的servlet容器中运行应用程序。但是,它不依赖于Spring MVC或Spring Web堆栈的其余部分,因此可以在任何servlet应用程序中使用,例如使用JAX-RS的应用程序。

 

Method Security(方法安全)

As well as support for securing web applications, Spring Security offers support for applying access rules to Java method executions. For Spring Security this is just a different type of "protected resource". For users it means the access rules are declared using the same format of ConfigAttribute strings (e.g. roles or expressions), but in a different place in your code. The first step is to enable method security, for example in the top level configuration for our app:

除了支持保护Web应用程序外,Spring Security还支持将访问规则应用于Java方法执行。对于Spring Security,这只是一种不同类型的“受保护资源”。对于用户来说,这意味着使用相同格式的ConfigAttribute字符串(例如角色或表达式)声明访问规则,但是在代码中的不同位置。第一步是启用方法安全性,例如在我们的应用程序的顶级配置中:
@SpringBootApplication
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SampleSecureApplication {
}

Then we can decorate the method resources directly, e.g.

然后我们可以直接装饰方法资源,例如
 
@Service
public class MyService {

  @Secured("ROLE_USER")
  public String secure() {
    return "Hello Security";
  }

}

This sample is a service with a secure method. If Spring creates a @Bean of this type then it will be proxied and callers will have to go through a security interceptor before the method is actually executed. If the access is denied the caller will get an AccessDeniedException instead of the actual method result.

此示例是具有安全方法的服务。如果Spring创建了这种类型的@Bean,那么它将被代理,并且调用者必须在实际执行该方法之前通过安全拦截器。如果访问被拒绝,则调用者将获得AccessDeniedException而不是实际的方法结果。
 
There are other annotations that can be used on methods to enforce security constraints, notably @PreAuthorize and @PostAuthorize, which allow you to write expressions containing references to method parameters and return values respectively.
 
还有其他注释可用于强制执行安全性约束的方法,特别是@PreAuthorize和@PostAuthorize,它们允许您编写包含对方法参数和返回值的引用的表达式。
 
 
Tip
It is not uncommon to combine Web security and method security. The filter chain provides the user experience features, like authentication and redirect to login pages etc, and the method security provides protection at a more granular level.

将Web安全性和方法安全性结合起来并不罕见。过滤器链提供用户体验功能,如身份验证和重定向到登录页面等,方法安全性可在更细粒度的级别提供保护。

 

Working with Threads(工作线程)

Spring Security is fundamentally thread bound because it needs to make the current authenticated principal available to a wide variety of downstream consumers. The basic building block is the SecurityContext which may contain an Authentication (and when a user is logged in it will be an Authenticationthat is explicitly authenticated). You can always access and manipulate the SecurityContext via static convenience methods in SecurityContextHolderwhich in turn simply manipulate a TheadLocal, e.g.

Spring Security基本上是线程绑定的,因为它需要使当前经过身份验证的主体可供各种下游消费者使用。基本构建块是SecurityContext,它可能包含身份验证(当用户登录时,它将是显式Authentication的authenticated)。您始终可以通过SecurityContextHolder中的静态便捷方法访问和操作SecurityContext,而SecurityContextHolder又可以简单地操作TheadLocal,例如:
 
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert(authentication.isAuthenticated);

 

It is not common for user application code to do this, but it can be useful if you, for instance, need to write a custom authentication filter (although even then there are base classes in Spring Security that can be used where you would avoid needing to use the SecurityContextHolder).

用户应用程序代码执行此操作并不常见,但是如果您需要编写自定义身份验证筛选器(例如,即使这样,Spring Security中的基类也可以在您避免需要的地方SecurityContextHolder)。
 
If you need access to the currently authenticated user in a web endpoint, you can use a method parameter in a @RequestMapping. E.g.
如果需要访问Web端点中当前经过身份验证的用户,则可以在@RequestMapping中使用方法参数。例如。
 
 
@RequestMapping("/foo")
public String foo(@AuthenticationPrincipal User user) {
  ... // do stuff with user
}

 

This annotation pulls the current Authentication out of the SecurityContextand calls the getPrincipal() method on it to yield the method parameter. The type of the Principal in an Authentication is dependent on the AuthenticationManager used to validate the authentication, so this can be a useful little trick to get a type safe reference to your user data.

此批注将当前的Authentication从SecurityContext中拉出,并在其上调用getPrincipal()方法以生成方法参数。身份验证中的Principal类型取决于用于验证身份验证的AuthenticationManager,因此这对于获取对用户数据的类型安全引用可能是一个有用的小技巧。
 
If Spring Security is in use the Principal from the HttpServletRequest will be of type Authentication, so you can also use that directly:
 
如果正在使用Spring Security,HttpServletRequest中的Principal将是Authentication类型,因此您也可以直接使用它:
 
@RequestMapping("/foo")
public String foo(Principal principal) {
  Authentication authentication = (Authentication) principal;
  User = (User) authentication.getPrincipal();
  ... // do stuff with user
}

 

This can sometimes be useful if you need to write code that works when Spring Security is not in use (you would need to be more defensive about loading the Authentication class).

 

如果您需要编写在Spring Security未使用时有效的代码(在加载Authentication类时需要更加防御),这有时会很有用。
 
 

Processing Secure Methods Asynchronously(异步处理安全方法)

Since the SecurityContext is thread bound, if you want to do any background processing that calls secure methods, e.g. with @Async, you need to ensure that the context is propagated. This boils down to wrapping the SecurityContext up with the task (RunnableCallable etc.) that is executed in the background. Spring Security provides some helpers to make this easier, such as wrappers for Runnable and Callable. To propagate the SecurityContext to @Asyncmethods you need to supply an AsyncConfigurer and ensure the Executor is of the correct type:

由于SecurityContext是线程绑定的,因此如果要进行任何调用安全方法的后台处理,例如使用@Async,您需要确保传播上下文。这归结为使用在后台执行的任务(Runnable,Callable等)包装SecurityContext。 Spring Security提供了一些帮助,使其更容易,例如Runnable和Callable的包装器。要将SecurityContext传播到@Async方法,您需要提供AsyncConfigurer并确保Executor的类型正确:
 
 
@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport {

  @Override
  public Executor getAsyncExecutor() {
    return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
  }

}
posted @ 2018-12-13 21:52  帅LOVE俊  阅读(426)  评论(1编辑  收藏  举报