Once you are familiar with setting up and running some namespace-configuration based applications, you may wish to develop more of an understanding of how the framework actually works behind the namespace facade. Like most software, Spring Security has certain central interfaces, classes and conceptual abstractions that are commonly used throughout the framework. In this part of the reference guide we will look at some of these and see how they work together to support authentication and access-control within Spring Security.html
架構和實現java
一旦您熟悉了設置和運行一些基於名稱空間配置的應用程序,您可能但願進一步瞭解框架在名稱空間背後的實際工做方式。與大多數軟件同樣,Spring Security具備某些在整個框架中廣泛使用的中央接口、類和概念抽象。在參考指南的這一部分中,咱們將研究其中的一些,並瞭解它們如何協同工做來支持Spring Security中的身份驗證和訪問控制。web
Spring Security 3.0 requires a Java 5.0 Runtime Environment or higher. As Spring Security aims to operate in a self-contained manner, there is no need to place any special configuration files into your Java Runtime Environment. In particular, there is no need to configure a special Java Authentication and Authorization Service (JAAS) policy file or place Spring Security into common classpath locations.spring
Similarly, if you are using an EJB Container or Servlet Container there is no need to put any special configuration files anywhere, nor include Spring Security in a server classloader. All the required files will be contained within your application.數據庫
This design offers maximum deployment time flexibility, as you can simply copy your target artifact (be it a JAR, WAR or EAR) from one system to another and it will immediately work.express
8.1.1 運行時環境數組
Spring Security 3.0須要Java 5.0或更高的運行時環境。因爲Spring Security旨在以自包含的方式進行操做,所以不須要在Java運行時環境中放置任何特殊的配置文件。特別是,不須要配置特殊的Java身份驗證和受權服務(JAAS)策略文件,也不須要將Spring安全性放到公共類路徑位置。安全
相似地,若是您使用EJB容器或Servlet容器,則不須要在任何地方放置任何特殊配置文件,也不須要在服務器類加載器中包含Spring安全性。全部必需的文件都將包含在應用程序中。服務器
這種設計提供了最大的部署時間靈活性,由於您能夠簡單地將目標工件(不論是JAR、WAR仍是EAR)從一個系統複製到另外一個系統,而且它能夠當即工做。架構
In Spring Security 3.0, the contents of the spring-security-core
jar were stripped down to the bare minimum. It no longer contains any code related to web-application security, LDAP or namespace configuration. We’ll take a look here at some of the Java types that you’ll find in the core module. They represent the building blocks of the framework, so if you ever need to go beyond a simple namespace configuration then it’s important that you understand what they are, even if you don’t actually need to interact with them directly.
8.1.2 核心組件
在Spring Security 3.0中,Spring-Security-core
jar 的內容被精簡到最少。它再也不包含任何與web應用程序安全性、LDAP或名稱空間配置相關的代碼。咱們將在這裏查看在覈心模塊中找到的一些Java類型。它們表示框架的構建塊,所以,若是您須要超越簡單的名稱空間配置,那麼理解它們是什麼很是重要,即便您實際上不須要直接與它們交互。
The most fundamental object is SecurityContextHolder
. This is where we store details of the present security context of the application, which includes details of the principal currently using the application. By default the SecurityContextHolder
uses a ThreadLocal
to store these details, which means that the security context is always available to methods in the same thread of execution, even if the security context is not explicitly passed around as an argument to those methods. Using a ThreadLocal in this way is quite safe if care is taken to clear the thread after the present principal’s request is processed. Of course, Spring Security takes care of this for you automatically so there is no need to worry about it.
Some applications aren’t entirely suitable for using a ThreadLocal
, because of the specific way they work with threads. For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context. SecurityContextHolder
can be configured with a strategy on startup to specify how you would like the context to be stored. For a standalone application you would use the SecurityContextHolder.MODE_GLOBAL
strategy. Other applications might want to have threads spawned by the secure thread also assume the same security identity. This is achieved by using SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
. You can change the mode from the default SecurityContextHolder.MODE_THREADLOCAL
in two ways. The first is to set a system property, the second is to call a static method on SecurityContextHolder
. Most applications won’t need to change from the default, but if you do, take a look at the JavaDoc for SecurityContextHolder
to learn more.
最基本的對象是 SecurityContextHolder
。這裏存儲應用程序當前安全上下文的詳細信息,其中包括當前使用該應用程序的主體的詳細信息。默認狀況下,SecurityContextHolder
使用一個ThreadLocal
來存儲這些細節,這意味着安全上下文對於同一執行線程中的方法老是可用的,即便安全上下文沒有做爲參數顯式地傳遞給這些方法。若是在處理當前主體的請求以後當心地清除線程,那麼以這種方式使用ThreadLocal
是很是安全的。固然,Spring Security會自動爲您處理這些問題,所以無需擔憂。
有些應用程序並不徹底適合使用ThreadLocal
,由於它們使用線程的特定方式。例如,Swing客戶機可能但願Java虛擬機中的全部線程使用相同的安全上下文。SecurityContextHolder
能夠在啓動時配置策略,以指定但願如何存儲上下文。對於獨立的應用程序,您將使用SecurityContextHolder.MODE_GLOBAL
策略。其餘應用程序可能但願由安全線程派生的線程也具備相同的安全標識。這是經過使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
實現的。您能夠從默認的SecurityContextHolder.MODE_THREADLOCAL
經過兩種方式去改變。第一個是設置系統屬性,第二個是調用SecurityContextHolder
上的靜態方法。大多數應用程序不須要更改默認值,可是若是須要更改,請查看SecurityContextHolder
的JavaDoc以瞭解更多信息。
Inside the SecurityContextHolder
we store details of the principal currently interacting with the application. Spring Security uses an Authentication
object to represent this information. You won’t normally need to create an Authentication
object yourself, but it is fairly common for users to query the Authentication
object. You can use the following code block - from anywhere in your application - to obtain the name of the currently authenticated user, for example:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof UserDetails) { String username = ((UserDetails)principal).getUsername(); } else { String username = principal.toString(); }
The object returned by the call to getContext()
is an instance of the SecurityContext
interface. This is the object that is kept in thread-local storage. As we’ll see below, most authentication mechanisms within Spring Security return an instance of UserDetails
as the principal.
獲取關於當前用戶的信息
在SecurityContextHolder
中,咱們存儲當前與應用程序交互的主體的詳細信息。Spring Security使用身份驗證對象表示此信息。您一般不須要本身建立身份驗證對象,可是用戶查詢Authentication object
是至關常見的。您能夠從應用程序中的任何位置使用如下代碼塊獲取當前已驗證用戶的名稱,例如:
調用getContext()
返回的對象是SecurityContext
接口的一個實例。這是保存在線程本地存儲中的對象。正如咱們將在下面看到的,Spring Security中的大多數身份驗證機制都返回一個UserDetails
實例做爲主體。
Another item to note from the above code fragment is that you can obtain a principal from the Authentication
object. The principal is just an Object
. Most of the time this can be cast into a UserDetails
object. UserDetails
is a core interface in Spring Security. It represents a principal, but in an extensible and application-specific way. Think of UserDetails
as the adapter between your own user database and what Spring Security needs inside the SecurityContextHolder
. Being a representation of something from your own user database, quite often you will cast the UserDetails
to the original object that your application provided, so you can call business-specific methods (like getEmail()
, getEmployeeNumber()
and so on).
By now you’re probably wondering, so when do I provide a UserDetails
object? How do I do that? I thought you said this thing was declarative and I didn’t need to write any Java code - what gives? The short answer is that there is a special interface called UserDetailsService
. The only method on this interface accepts a String
-based username argument and returns a UserDetails
:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
This is the most common approach to loading information for a user within Spring Security and you will see it used throughout the framework whenever information on a user is required.
On successful authentication, UserDetails
is used to build the Authentication
object that is stored in the SecurityContextHolder
(more on this below). The good news is that we provide a number of UserDetailsService
implementations, including one that uses an in-memory map (InMemoryDaoImpl
) and another that uses JDBC (JdbcDaoImpl
). Most users tend to write their own, though, with their implementations often simply sitting on top of an existing Data Access Object (DAO) that represents their employees, customers, or other users of the application. Remember the advantage that whatever your UserDetailsService
returns can always be obtained from the SecurityContextHolder
using the above code fragment.
從上面的代碼片斷中須要注意的另外一項是,您能夠從Authentication
對象中獲取主體。主體只是一個對象。大多數狀況下,這能夠轉換爲UserDetails
對象。UserDetails
是Spring Security中的一個核心接口。它表示主體,可是是以可擴展的和特定於應用程序的方式。將UserDetails
視爲您本身的用戶數據庫和Spring Security須要的SecurityContextHolder
之間的適配器。做爲來自您本身的用戶數據庫的內容的表示,您常常會將UserDetails
轉換爲您的應用程序提供的原始對象,所以您能夠調用特定於業務的方法(如getEmail()、getEmployeeNumber()等)。
如今您可能想知道,我何時提供UserDetails對象?我該怎麼作呢?我記得你說過這個東西是聲明性的,我不須要編寫任何Java代碼——這是怎麼回事?簡單地說,有一個名爲UserDetailsService的特殊接口。這個接口上惟一的方法接受一個基於字符串的username參數,並返回一個UserDetails
:
這是在Spring Security中爲用戶加載信息的最多見方法,在須要用戶信息時,您將看到它在整個框架中使用。
在成功進行身份驗證時,UserDetails用於構建存儲在SecurityContextHolder
中的身份驗證對象(下面將對此進行詳細介紹)。好消息是咱們提供了許多UserDetailsService實現,包括一個使用內存映射(InMemoryDaoImpl)的實現和另外一個使用JDBC (JdbcDaoImpl)的實現。可是,大多數用戶傾向於編寫本身的實現,他們的實現一般只是位於表明他們的僱員、客戶或應用程序的其餘用戶的現有數據訪問對象(DAO)之上。記住,不管UserDetailsService返回什麼,均可以使用上面的代碼片斷從SecurityContextHolder
得到。
There is often some confusion aboutUserDetailsService
. It is purely a DAO for user data and performs no other function other than to supply that data to other components within the framework. In particular, it does not authenticate the user, which is done by theAuthenticationManager
. In many cases it makes more sense to implement AuthenticationProvider directly if you require a custom authentication process.關於
UserDetailsService
常常會有一些混淆。它純粹是一個用於用戶數據的DAO,除了向框架內的其餘組件提供數據以外,不執行任何其餘功能。特別是,它不驗證用戶,這是由AuthenticationManager
完成的。在許多狀況下,若是須要自定義身份驗證過程,則直接實現AuthenticationProvider
更有意義。
Besides the principal, another important method provided by Authentication
is getAuthorities()
. This method provides an array of GrantedAuthority
objects. A GrantedAuthority
is, not surprisingly, an authority that is granted to the principal. Such authorities are usually "roles", such as ROLE_ADMINISTRATOR
or ROLE_HR_SUPERVISOR
. These roles are later on configured for web authorization, method authorization and domain object authorization. Other parts of Spring Security are capable of interpreting these authorities, and expect them to be present. GrantedAuthority
objects are usually loaded by the UserDetailsService
.
Usually the GrantedAuthority
objects are application-wide permissions. They are not specific to a given domain object. Thus, you wouldn’t likely have a GrantedAuthority
to represent a permission to Employee
object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user). Of course, Spring Security is expressly designed to handle this common requirement, but you’d instead use the project’s domain object security capabilities for this purpose.
除了主體以外,Authentication
提供的另外一個重要方法是getAuthorities()
。該方法提供了一個GrantedAuthority對象數組。授予的權限是授予主體的權限,這並不奇怪。這些權限一般是「角色」,例如ROLE_ADMINISTRATOR
或ROLE_HR_SUPERVISOR
。稍後將爲web受權、方法受權和域對象受權配置這些角色。Spring Security的其餘部分可以解釋這些權限,並但願它們可以出現。GrantedAuthority
對象一般由UserDetailsService
加載。
一般GrantedAuthority
的對象是應用程序範圍的權限。它們並不特定於給定的域對象。所以,您不太可能得到GrantedAuthority
來表示Employee
對象54的權限,由於若是有數千個這樣的權限,您將很快耗盡內存(或者,至少會致使應用程序花很長時間來驗證用戶)。固然,Spring Security是專門爲處理這種常見需求而設計的,可是您能夠爲此使用項目的域對象安全功能。
Just to recap, the major building blocks of Spring Security that we’ve seen so far are:
SecurityContextHolder
, to provide access to the SecurityContext
.SecurityContext
, to hold the Authentication
and possibly request-specific security information.Authentication
, to represent the principal in a Spring Security-specific manner.GrantedAuthority
, to reflect the application-wide permissions granted to a principal.UserDetails
, to provide the necessary information to build an Authentication object from your application’s DAOs or other source of security data.UserDetailsService
, to create a UserDetails
when passed in a String
-based username (or certificate ID or the like).Now that you’ve gained an understanding of these repeatedly-used components, let’s take a closer look at the process of authentication.
簡單回顧一下,到目前爲止咱們所看到的Spring安全的主要構建塊是:
SecurityContextHolder
提供對SecurityContext
的接入。SecurityContext
,以保存Authentication
和多是特定於請求的安全信息。Authentication
,以特定於Spring安全的方式表示主體。GrantedAuthority
,以反映授予主體的應用程序範圍的權限。UserDetails
,以提供從應用程序的dao或其餘安全數據源構建身份驗證對象所需的信息。UserDetailsService
,用於在傳入基於字符串的用戶名(或證書ID或相似的名稱)時建立用戶詳細信息。如今您已經瞭解了這些重複使用的組件,接下來讓咱們進一步瞭解身份驗證的過程。