Spring Security(三十二):10. Core Services

Now that we have a high-level overview of the Spring Security architecture and its core classes, let’s take a closer look at one or two of the core interfaces and their implementations, in particular the AuthenticationManagerUserDetailsService and the AccessDecisionManager. These crop up regularly throughout the remainder of this document so it’s important you know how they are configured and how they operate.html

如今咱們對Spring Security體系結構及其核心類進行了高級概述,讓咱們仔細研究一個或兩個核心接口及其實現,特別是AuthenticationManager,UserDetailsS​​ervice和AccessDecisionManager。這些文件會在本文檔的其他部分按期出現,所以瞭解它們的配置方式以及它們的運行方式很是重要。

10.1 The AuthenticationManager, ProviderManager and AuthenticationProvider

The AuthenticationManager is just an interface, so the implementation can be anything we choose, but how does it work in practice? What if we need to check multiple authentication databases or a combination of different authentication services such as a database and an LDAP server?java

AuthenticationManager只是一個接口,所以實現能夠是咱們選擇的任何東西,但它在實踐中如何工做?若是咱們須要檢查多個身份驗證數據庫或不一樣身份驗證服務(如數據庫和LDAP服務器)的組合,該怎麼辦?
 
The default implementation in Spring Security is called  ProviderManager and rather than handling the authentication request itself, it delegates to a list of configured  AuthenticationProvider s, each of which is queried in turn to see if it can perform the authentication. Each provider will either throw an exception or return a fully populated  Authentication object. Remember our good friends,  UserDetails and  UserDetailsService? If not, head back to the previous chapter and refresh your memory. The most common approach to verifying an authentication request is to load the corresponding  UserDetails and check the loaded password against the one that has been entered by the user. This is the approach used by the  DaoAuthenticationProvider (see below). The loaded  UserDetails object - and particularly the  GrantedAuthority s it contains - will be used when building the fully populated  Authentication object which is returned from a successful authentication and stored in the  SecurityContext.
Spring Security中的默認實現稱爲ProviderManager,它不是處理身份驗證請求自己,而是委託給已配置的AuthenticationProvider列表,每一個查詢器依次查詢它們是否能夠執行身份驗證。每一個提供程序將拋出異​​常或返回徹底填充的Authentication對象。還記得咱們的好朋友,UserDetails和UserDetailsS​​ervice嗎?若是沒有,請回到上一章並刷新記憶。驗證身份驗證請求的最經常使用方法是加載相應的UserDetails並檢查加載的密碼與用戶輸入的密碼。這是DaoAuthenticationProvider使用的方法(見下文)。加載的UserDetails對象 - 特別是它包含的GrantedAuthority - 將在構建徹底填充的Authentication對象時使用,該對象從成功的身份驗證返回並存儲在SecurityContext中。
 
If you are using the namespace, an instance of  ProviderManager is created and maintained internally, and you add providers to it by using the namespace authentication provider elements (see  the namespace chapter). In this case, you should not declare a  ProviderManager bean in your application context. However, if you are not using the namespace then you would declare it like so:
若是您正在使用命名空間,則會在內部建立和維護ProviderManager的實例,並使用命名空間身份驗證提供程序元素向其添加提供程序(請參閱命名空間章節)。在這種狀況下,您不該在應用程序上下文中聲明ProviderManager bean。可是,若是您沒有使用命名空間,那麼您將聲明它以下:
 
<bean id="authenticationManager"
		class="org.springframework.security.authentication.ProviderManager">
	<constructor-arg>
		<list>
			<ref local="daoAuthenticationProvider"/>
			<ref local="anonymousAuthenticationProvider"/>
			<ref local="ldapAuthenticationProvider"/>
		</list>
	</constructor-arg>
</bean>

In the above example we have three providers. They are tried in the order shown (which is implied by the use of a List), with each provider able to attempt authentication, or skip authentication by simply returning null. If all implementations return null, the ProviderManager will throw a ProviderNotFoundException. If you’re interested in learning more about chaining providers, please refer to the ProviderManager Javadoc.web

在上面的例子中,咱們有三個提供者。它們按所示順序(使用List暗示)進行嘗試,每一個提供程序均可以嘗試進行身份驗證,或者經過簡單地返回null來跳過身份驗證。若是全部實現都返回null,則ProviderManager將拋出ProviderNotFoundException。若是您有興趣瞭解有關連接提供程序的更多信息,請參閱ProviderManager Javadoc。
 
Authentication mechanisms such as a web form-login processing filter are injected with a reference to the  ProviderManager and will call it to handle their authentication requests. The providers you require will sometimes be interchangeable with the authentication mechanisms, while at other times they will depend on a specific authentication mechanism. For example,  DaoAuthenticationProvider and  LdapAuthenticationProvider are compatible with any mechanism which submits a simple username/password authentication request and so will work with form-based logins or HTTP Basic authentication. 
諸如Web表單登陸處理過濾器之類的身份驗證機制將引用ProviderManager,並將其調用以處理其身份驗證請求。您須要的提供程序有時能夠與身份驗證機制互換,而在其餘時候,它們將依賴於特定的身份驗證機制。例如,DaoAuthenticationProvider和LdapAuthenticationProvider與提交簡單用戶名/密碼身份驗證請求的任何機制兼容,所以可使用基於表單的登陸或HTTP基自己份驗證。
 
On the other hand, some authentication mechanisms create an authentication request object which can only be interpreted by a single type of  AuthenticationProvider. An example of this would be JA-SIG CAS, which uses the notion of a service ticket and so can therefore only be authenticated by a  CasAuthenticationProvider. You needn’t be too concerned about this, because if you forget to register a suitable provider, you’ll simply receive a  ProviderNotFoundException when an attempt to authenticate is made.
另外一方面,某些身份驗證機制會建立一個身份驗證請求對象,該對象只能由單一類型的AuthenticationProvider進行解釋。這方面的一個例子是JA-SIG CAS,它使用服務票據的概念,所以只能由CasAuthenticationProvider進行身份驗證。您沒必要過於擔憂這一點,由於若是您忘記註冊合適的提供程序,那麼在嘗試進行身份驗證時,您只會收到ProviderNotFoundException。

10.1.1 Erasing Credentials on Successful Authentication

By default (from Spring Security 3.1 onwards) the ProviderManager will attempt to clear any sensitive credentials information from the Authentication object which is returned by a successful authentication request. This prevents information like passwords being retained longer than necessary.spring

默認狀況下(從Spring Security 3.1起),ProviderManager將嘗試從Authentication對象中清除任何敏感憑證信息,該信息由成功的身份驗證請求返回。這能夠防止密碼保留的時間超過必要的時間。
 
This may cause issues when you are using a cache of user objects, for example, to improve performance in a stateless application. If the  Authentication contains a reference to an object in the cache (such as a  UserDetails instance) and this has its credentials removed, then it will no longer be possible to authenticate against the cached value. You need to take this into account if you are using a cache. An obvious solution is to make a copy of the object first, either in the cache implementation or in the  AuthenticationProvider which creates the returned  Authentication object. Alternatively, you can disable the  eraseCredentialsAfterAuthenticationproperty on  ProviderManager. See the Javadoc for more information.
當您使用用戶對象的緩存時,這可能會致使問題,例如,提升無狀態應用程序的性能。若是身份驗證包含對緩存中對象的引用(例如UserDetails實例)而且已刪除其憑據,則將沒法再對緩存的值進行身份驗證。若是使用緩存,則須要考慮這一點。一個顯而易見的解決方案是首先在緩存實現中或在建立返回的Authentication對象的AuthenticationProvider中製做對象的副本。或者,您能夠在ProviderManager上禁用eraseCredentialsAfterAuthentication屬性。有關更多信息,請參閱Javadoc。
 

10.1.2 DaoAuthenticationProvider

The simplest AuthenticationProvider implemented by Spring Security is DaoAuthenticationProvider, which is also one of the earliest supported by the framework. It leverages a UserDetailsService (as a DAO) in order to lookup the username, password and GrantedAuthority s. It authenticates the user simply by comparing the password submitted in a UsernamePasswordAuthenticationToken against the one loaded by the UserDetailsService. Configuring the provider is quite simple:sql

Spring Security實現的最簡單的AuthenticationProvider是DaoAuthenticationProvider,它也是該框架最先支持的之一。它利用UserDetailsS​​ervice(做爲DAO)來查找用戶名,密碼和GrantedAuthority。它只是經過將UsernamePasswordAuthenticationToken中提交的密碼與UserDetailsS​​ervice加載的密碼進行比較來對用戶進行身份驗證。配置提供程序很是簡單:
 
<bean id="daoAuthenticationProvider"
	class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
<property name="passwordEncoder" ref="passwordEncoder"/>
</bean>

The PasswordEncoder is optional. A PasswordEncoder provides encoding and decoding of passwords presented in the UserDetails object that is returned from the configured UserDetailsService. This will be discussed in more detail below.數據庫

PasswordEncoder是可選的。 PasswordEncoder提供從配置的UserDetailsS​​ervice返回的UserDetails對象中顯示的密碼的編碼和解碼。這將在下面更詳細地討論。

10.2 UserDetailsService Implementations

As mentioned in the earlier in this reference guide, most authentication providers take advantage of the UserDetails and UserDetailsService interfaces. Recall that the contract for UserDetailsService is a single method:緩存

如本參考指南前面所述,大多數身份驗證提供程序都利用UserDetails和UserDetailsS​​ervice接口。回想一下UserDetailsS​​ervice的合同是一個單一的方法:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

The returned UserDetails is an interface that provides getters that guarantee non-null provision of authentication information such as the username, password, granted authorities and whether the user account is enabled or disabled. Most authentication providers will use a UserDetailsService, even if the username and password are not actually used as part of the authentication decision. They may use the returned UserDetails object just for its GrantedAuthority information, because some other system (like LDAP or X.509 or CAS etc) has undertaken the responsibility of actually validating the credentials.安全

返回的UserDetails是一個接口,提供保證非空提供身份驗證信息的getter,例如用戶名,密碼,授予的權限以及是啓用仍是禁用用戶賬戶。大多數身份驗證提供程序將使用UserDetailsS​​ervice,即便用戶名和密碼實際上未用做身份驗證決策的一部分。他們可能僅僅爲了GrantedAuthority信息使用返回的UserDetails對象,由於其餘一些系統(如LDAP或X.509或CAS等)承擔了實際驗證憑據的責任。
 
Given  UserDetailsService is so simple to implement, it should be easy for users to retrieve authentication information using a persistence strategy of their choice. Having said that, Spring Security does include a couple of useful base implementations, which we’ll look at below.
鑑於UserDetailsS​​ervice實現起來很是簡單,用戶應該可使用本身選擇的持久性策略輕鬆檢索身份驗證信息。話雖如此,Spring Security確實包含了一些有用的基礎實現,咱們將在下面介紹。

10.2.1 In-Memory Authentication

Is easy to use create a custom UserDetailsService implementation that extracts information from a persistence engine of choice, but many applications do not require such complexity. This is particularly true if you’re building a prototype application or just starting integrating Spring Security, when you don’t really want to spend time configuring databases or writing UserDetailsService implementations. For this sort of situation, a simple option is to use the user-service element from the security namespace:服務器

易於使用建立自定義UserDetailsS​​ervice實現,從實際選擇的持久性引擎中提取信息,但許多應用程序不須要這樣的複雜性。若是您正在構建原型應用程序或剛剛開始集成Spring Security,而您真的不想花時間配置數據庫或編寫UserDetailsS​​ervice實現,則尤爲如此。對於這種狀況,一個簡單的選擇是使用安全命名空間中的user-service元素:
 
<user-service id="userDetailsService">
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>

This also supports the use of an external properties file:架構

這也支持使用外部屬性文件:
 
<user-service id="userDetailsService" properties="users.properties"/>

The properties file should contain entries in the form

屬性文件應包含表單中的條目
username=password,grantedAuthority[,grantedAuthority][,enabled|disabled]

For example

jimi=jimispassword,ROLE_USER,ROLE_ADMIN,enabled
bob=bobspassword,ROLE_USER,enabled

10.2.2 JdbcDaoImpl

Spring Security also includes a UserDetailsService that can obtain authentication information from a JDBC data source. Internally Spring JDBC is used, so it avoids the complexity of a fully-featured object relational mapper (ORM) just to store user details. If your application does use an ORM tool, you might prefer to write a custom UserDetailsService to reuse the mapping files you’ve probably already created. Returning to JdbcDaoImpl, an example configuration is shown below:

Spring Security還包括一個UserDetailsS​​ervice,它能夠從JDBC數據源獲取身份驗證信息。內部使用Spring JDBC,所以它避免了全功能對象關係映射器(ORM)的複雜性,只是爲了存儲用戶詳細信息。若是您的應用程序確實使用ORM工具,您可能更願意編寫自定義UserDetailsS​​ervice來重用您可能已經建立的映射文件。返回JdbcDaoImpl,示例配置以下所示:
 
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>

<bean id="userDetailsService"
	class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

You can use different relational database management systems by modifying the DriverManagerDataSource shown above. You can also use a global data source obtained from JNDI, as with any other Spring configuration.

您能夠經過修改上面顯示的DriverManagerDataSource來使用不一樣的關係數據庫管理系統。您還可使用從JNDI獲取的全局數據源,與任何其餘Spring配置同樣。

Authority Groups

By default, JdbcDaoImpl loads the authorities for a single user with the assumption that the authorities are mapped directly to users (see the database schema appendix). An alternative approach is to partition the authorities into groups and assign groups to the user. Some people prefer this approach as a means of administering user rights. See the JdbcDaoImpl Javadoc for more information on how to enable the use of group authorities. The group schema is also included in the appendix.

默認狀況下,JdbcDaoImpl爲單個用戶加載權限,並假設權限直接映射到用戶(請參閱數據庫模式附錄)。另外一種方法是將權限劃分爲組並將組分配給用戶。有些人更喜歡這種方法來管理用戶權利。有關如何啓用組權限的更多信息,請參閱JdbcDaoImpl Javadoc。組架構也包含在附錄中。
相關文章
相關標籤/搜索