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()
老是返回一個新的上下文實例。