Now let’s explore the situation where you are using Spring Security in a web application (without web.xml
security enabled). How is a user authenticated and the security context established?web
如今让咱们研究一下在web应用程序中使用Spring安全性的状况(没有web.xml安全启用)。如何对用户进行身份验证并创建安全上下文?浏览器
Consider a typical web application’s authentication process:安全
考虑一个典型的web应用程序的身份验证过程:服务器
Spring Security has distinct classes responsible for most of the steps described above. The main participants (in the order that they are used) are the ExceptionTranslationFilter
, an AuthenticationEntryPoint
and an "authentication mechanism", which is responsible for calling the AuthenticationManager
which we saw in the previous section.cookie
Spring Security有不一样的类负责上面描述的大多数步骤。主要参与者(按使用顺序)是ExceptionTranslationFilter、AuthenticationEntryPoint和“身份验证机制”,该机制负责调用咱们在上一节中看到的authenticationmanager。session
ExceptionTranslationFilter
is a Spring Security filter that has responsibility for detecting any Spring Security exceptions that are thrown. Such exceptions will generally be thrown by an AbstractSecurityInterceptor
, which is the main provider of authorization services. We will discuss AbstractSecurityInterceptor
in the next section, but for now we just need to know that it produces Java exceptions and knows nothing about HTTP or how to go about authenticating a principal. Instead the ExceptionTranslationFilter
offers this service, with specific responsibility for either returning error code 403 (if the principal has been authenticated and therefore simply lacks sufficient access - as per step seven above), or launching an AuthenticationEntryPoint
(if the principal has not been authenticated and therefore we need to go commence step three).并发
ExceptionTranslationFilter是一个Spring安全过滤器,它负责检测抛出的任何Spring安全异常。此类异常一般由AbstractSecurityInterceptor抛出,它是受权服务的主要提供者。咱们将在下一节讨论AbstractSecurityInterceptor,可是如今咱们只须要知道它会产生Java异常,而且不知道HTTP或如何对主体进行身份验证。相反ExceptionTranslationFilter提供这种服务,具体负责返回错误代码403(若是校长已通过身份验证的,所以只是缺少足够的访问——按步骤7),或启动一个AuthenticationEntryPoint(若是委托人尚未通过身份验证的,所以咱们要开始第三步)。app
The AuthenticationEntryPoint
is responsible for step three in the above list. As you can imagine, each web application will have a default authentication strategy (well, this can be configured like nearly everything else in Spring Security, but let’s keep it simple for now). Each major authentication system will have its own AuthenticationEntryPoint
implementation, which typically performs one of the actions described in step 3.less
AuthenticationEntryPoint负责上述列表中的第三步。正如您能够想象的那样,每一个web应用程序都有一个默认的身份验证策略(这个策略能够像Spring Security中的几乎全部其余策略同样配置,可是如今让咱们保持简单)。每一个主要的身份验证系统都有本身的AuthenticationEntryPoint实现,它一般执行步骤3中描述的操做之一。ide
Once your browser submits your authentication credentials (either as an HTTP form post or HTTP header) there needs to be something on the server that "collects" these authentication details. By now we’re at step six in the above list. In Spring Security we have a special name for the function of collecting authentication details from a user agent (usually a web browser), referring to it as the "authentication mechanism". Examples are form-base login and Basic authentication. Once the authentication
details have been collected from the user agent, an Authentication
"request" object is built and then presented to the AuthenticationManager
.
一旦浏览器提交了身份验证凭证(以HTTP表单post或HTTP header的形式),服务器上就须要“收集”这些身份验证细节。到目前为止,咱们已经完成了上述列表中的第6步。在Spring Security中,咱们为从用户代理(一般是web浏览器)收集身份验证细节的功能取了一个特殊的名称,将其称为“身份验证机制”。示例是基于表单的登陆和基自己份验证。从用户代理收集身份验证详细信息以后,将构建身份验证“请求”对象,而后将其呈现给AuthenticationManager。
After the authentication mechanism receives back the fully-populated Authentication
object, it will deem the request valid, put the Authentication
into the SecurityContextHolder, and cause the original request to be retried (step seven above). If, on the other hand, the AuthenticationManager
rejected the request, the authentication mechanism will ask the user agent to retry (step two above).
身份验证机制接收到完整填充的身份验证对象后,将认为请求有效,将Authentication
放入SecurityContextHolder
中,并致使从新尝试原始请求(上面的步骤7)。另外一方面,若是AuthenticationManager
拒绝请求,身份验证机制将要求用户代理重试(上面的步骤2)。
在请求之间存储SecurityContext
Depending on the type of application, there may need to be a strategy in place to store the security context between user operations. In a typical web application, a user logs in once and is subsequently identified by their session Id. The server caches the principal information for the duration session. In Spring Security, the responsibility for storing the SecurityContext
between requests falls to the SecurityContextPersistenceFilter
, which by default stores the context as an HttpSession attribute between HTTP requests. It restores the context to the SecurityContextHolder
for each request and, crucially, clears the SecurityContextHolder
when the request completes. You shouldn’t interact directly with the HttpSession
for security purposes. There is simply no justification for doing so - always use the SecurityContextHolder
instead.
根据应用程序的类型,可能须要适当的策略来存储用户操做之间的安全上下文。在典型的web应用程序中,用户登陆一次,而后由其会话Id标识。在Spring Security中,在请求之间存储SecurityContext的责任落在SecurityContextPersistenceFilter
身上,它在默认状况下将上下文做为HTTP请求之间的HttpSession属性存储。它将每一个请求的上下文恢复到SecurityContextHolder
,最重要的是,在请求完成时清除SecurityContextHolder
。出于安全目的,您不该该直接与HttpSession交互。这样作没有任何理由——老是使用SecurityContextHolder
。
Many other types of application (for example, a stateless RESTful web service) do not use HTTP sessions and will re-authenticate on every request. However, it is still important that the SecurityContextPersistenceFilter
is included in the chain to make sure that the SecurityContextHolder
is cleared after each request.
许多其余类型的应用程序(例如,无状态RESTful web服务)不使用HTTP会话,而是对每一个请求从新进行身份验证。可是,仍然须要在链中包含SecurityContextPersistenceFilter
,以确保在每一个请求以后清除SecurityContextHolder
。
In an application which receives concurrent requests in a single session, the sameSecurityContext
instance will be shared between threads. Even though aThreadLocal
is being used, it is the same instance that is retrieved from theHttpSession
for each thread. This has implications if you wish to temporarily change the context under which a thread is running. If you just useSecurityContextHolder.getContext()
, and callsetAuthentication(anAuthentication)
on the returned context object, then theAuthentication
object will change in all concurrent threads which share the sameSecurityContext
instance. You can customize the behaviour ofSecurityContextPersistenceFilter
to create a completely newSecurityContext
for each request, preventing changes in one thread from affecting another. Alternatively you can create a new instance just at the point where you temporarily change the context. The methodSecurityContextHolder.createEmptyContext()
always returns a new context instance.
在一个在单个会话中接收并发请求的应用程序中,相同的SecurityContext实例将在线程之间共享。尽管使用的是ThreadLocal,可是从HttpSession中为每一个线程检索的实例是相同的。若是您但愿临时更改线程所运行的上下文,那么这将产生影响。若是您只是使用SecurityContext.getcontext()
,并对返回的上下文对象调用setAuthentication(anAuthentication),那么身份验证对象将在共享相同SecurityContext实例的全部并发线程中发生变化。您能够自定义SecurityContextPersistenceFilter
的行为,为每一个请求建立一个全新的SecurityContext,防止一个线程中的更改影响另外一个线程。或者,您能够只在临时更改上下文的地方建立一个新实例。方法SecurityContextHolder.createemptycontext()
老是返回一个新的上下文实例。