Spring Security OAuth2 開發指南(非最新版本)

請注意哈,本文翻譯的時候,官網的的版本和本文翻譯的時候是一一對應的。
可是官網已經更新文檔和概念了,所以和本文翻譯的就不在是同一個範圍了。
所以我已經將標題修改成(非最新版本),各位老鐵直接看官網就能夠了,我之後有時間在翻譯更新一下。
官網的連接仍然沒變。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
翻譯及修改補充:Alex Liao.
轉載請註明來源:http://www.cnblogs.com/xingxueliao/p/5911292.html
 
Spring OAuth2.0 提供者實現原理:

Spring OAuth2.0提供者實際上分爲:
  • 受權服務 Authorization Service.
  • 資源服務 Resource Service.
雖然這兩個提供者有時候可能存在同一個應用程序中,但在Spring Security OAuth中你能夠把
他它們各自放在不一樣的應用上,並且你能夠有多個資源服務,它們共享同一個中央受權服
務。
 
全部獲取令牌的請求都將會在Spring MVC controller endpoints中進行處理,而且訪問受保護
的資源服務的處理流程將會放在標準的Spring Security請求過濾器中(filters)。
 
下面是配置一個受權服務必需要實現的endpoints:
  • AuthorizationEndpoint:用來做爲請求者得到受權的服務,默認的URL是/oauth/authorize.
  • TokenEndpoint:用來做爲請求者得到令牌(Token)的服務,默認的URL是/oauth/token.
 
下面是配置一個資源服務必需要實現的過濾器:
  • OAuth2AuthenticationProcessingFilter:用來做爲認證令牌(Token)的一個處理流程過濾器。只有當過濾器經過以後,請求者才能得到受保護的資源。
 
配置提供者(受權、資源)均可以經過簡單的Java註解@Configuration來進行適配,你也可使用基於XML的聲明式語法來進行配置,若是你打算這樣作的話,那麼請使用http://www.springframework.org/schema/security/spring-security-oauth2.xsd來做爲XML的schema(即XML概要定義)以及使用http://www.springframework.org/schema/security/oauth2來做爲命名空間。
 
 
1、受權服務配置:

配置一個受權服務,你須要考慮幾種受權類型(Grant Type),不一樣的受權類型爲客戶端(Client)提供了不一樣的獲取令牌(Token)方式,爲了實現並肯定這幾種受權,須要配置使用 ClientDetailsService 和 TokenService 來開啓或者禁用這幾種受權機制。到這裏就請注意了,無論你使用什麼樣的受權類型(Grant Type),每個客戶端(Client)都可以經過明確的配置以及權限來實現不一樣的受權訪問機制。這也就是說,假如你提供了一個支持"client_credentials"的受權方式,並不意味着客戶端就須要使用這種方式來得到受權。下面是幾種受權類型的列表,具體受權機制的含義能夠參見RFC6749( 中文版本):
  • authorization_code:受權碼類型。
  • implicit:隱式受權類型。
  • password:資源全部者(即用戶)密碼類型。
  • client_credentials:客戶端憑據(客戶端ID以及Key)類型。
  • refresh_token:經過以上受權得到的刷新令牌來獲取新的令牌。
 
能夠用 @EnableAuthorizationServer 註解來配置OAuth2.0 受權服務機制,經過使用@Bean註解的幾個方法一塊兒來配置這個受權服務。下面我們介紹幾個配置類,這幾個配置是由Spring建立的獨立的配置對象,它們會被Spring傳入AuthorizationServerConfigurer中:
  • ClientDetailsServiceConfigurer:用來配置客戶端詳情服務(ClientDetailsService),客戶端詳情信息在這裏進行初始化,你可以把客戶端詳情信息寫死在這裏或者是經過數據庫來存儲調取詳情信息。
  • AuthorizationServerSecurityConfigurer:用來配置令牌端點(Token Endpoint)的安全約束.
  • AuthorizationServerEndpointsConfigurer:用來配置受權(authorization)以及令牌(token)的訪問端點和令牌服務(token services)。
(譯者注:以上的配置能夠選擇繼承AuthorizationServerConfigurerAdapter而且覆寫其中的三個configure方法來進行配置。)
 
配置受權服務一個比較重要的方面就是提供一個受權碼給一個OAuth客戶端(經過 authorization_code 受權類型),一個受權碼的獲取是OAuth客戶端跳轉到一個受權頁面,而後經過驗證受權以後服務器重定向到OAuth客戶端,而且在重定向鏈接中附帶返回一個受權碼。
 
若是你是經過XML來進行配置的話,那麼可使用 <authorization-server/> 標籤來進行配置。
 
(譯者注:想一想如今國內各大平臺的社會化登錄服務,例如騰訊,用戶要使用QQ登陸到某個網站,這個網站是跳轉到了騰訊的登錄受權頁面,而後用戶登陸而且肯定受權以後跳轉回目標網站,這種受權方式規範在我上面提供的連接*RFC6749*的第4.1節有詳細闡述。)
 
配置客戶端詳情信息(Client Details):
ClientDetailsServiceConfigurer (AuthorizationServerConfigurer 的一個回調配置項,見上的概述) 可以使用內存或者JDBC來實現客戶端詳情服務(ClientDetailsService),有幾個重要的屬性以下列表:
  • clientId:(必須的)用來標識客戶的Id。
  • secret:(須要值得信任的客戶端)客戶端安全碼,若是有的話。
  • scope:用來限制客戶端的訪問範圍,若是爲空(默認)的話,那麼客戶端擁有所有的訪問範圍。
  • authorizedGrantTypes:此客戶端可使用的受權類型,默認爲空。
  • authorities:此客戶端可使用的權限(基於Spring Security authorities)。
 
客戶端詳情(Client Details)可以在應用程序運行的時候進行更新,能夠經過訪問底層的存儲服務(例如將客戶端詳情存儲在一個關係數據庫的表中,就可使用 JdbcClientDetailsService)或者經過 ClientDetailsManager 接口(同時你也能夠實現 ClientDetailsService 接口)來進行管理。
(譯者注:不過我並無找到 ClientDetailsManager 這個接口文件,只找到了 ClientDetailsService)
 
管理令牌(Managing Token):
AuthorizationServerTokenServices 接口定義了一些操做使得你能夠對令牌進行一些必要的管理,在使用這些操做的時候請注意如下幾點:
  • 當一個令牌被建立了,你必須對其進行保存,這樣當一個客戶端使用這個令牌對資源服務進行請求的時候纔可以引用這個令牌。
  • 當一個令牌是有效的時候,它能夠被用來加載身份信息,裏面包含了這個令牌的相關權限。
 
當你本身建立 AuthorizationServerTokenServices 這個接口的實現時,你可能須要考慮一下使用 DefaultTokenServices 這個類,裏面包含了一些有用實現,你可使用它來修改令牌的格式和令牌的存儲。默認的,當它嘗試建立一個令牌的時候,是使用隨機值來進行填充的,除了持久化令牌是委託一個 TokenStore 接口來實現之外,這個類幾乎幫你作了全部的事情。而且 TokenStore 這個接口有一個默認的實現,它就是 InMemoryTokenStore ,如其命名,全部的令牌是被保存在了內存中。除了使用這個類之外,你還可使用一些其餘的預約義實現,下面有幾個版本,它們都實現了TokenStore接口:
  • InMemoryTokenStore:這個版本的實現是被默認採用的,它能夠完美的工做在單服務器上(即訪問併發量壓力不大的狀況下,而且它在失敗的時候不會進行備份),大多數的項目均可以使用這個版本的實現來進行嘗試,你能夠在開發的時候使用它來進行管理,由於不會被保存到磁盤中,因此更易於調試。
  • JdbcTokenStore:這是一個基於JDBC的實現版本,令牌會被保存進關係型數據庫。使用這個版本的實現時,你能夠在不一樣的服務器之間共享令牌信息,使用這個版本的時候請注意把"spring-jdbc"這個依賴加入到你的classpath當中。
  • JwtTokenStore:這個版本的全稱是 JSON Web Token(JWT),它能夠把令牌相關的數據進行編碼(所以對於後端服務來講,它不須要進行存儲,這將是一個重大優點),可是它有一個缺點,那就是撤銷一個已經受權令牌將會很是困難,因此它一般用來處理一個生命週期較短的令牌以及撤銷刷新令牌(refresh_token)。另一個缺點就是這個令牌佔用的空間會比較大,若是你加入了比較多用戶憑證信息。JwtTokenStore 不會保存任何數據,可是它在轉換令牌值以及受權信息方面與 DefaultTokenServices 所扮演的角色是同樣的。
 
 
JWT令牌(JWT Tokens):
使用JWT令牌你須要在受權服務中使用 JwtTokenStore,資源服務器也須要一個解碼的Token令牌的類 JwtAccessTokenConverter,JwtTokenStore依賴這個類來進行編碼以及解碼,所以你的受權服務以及資源服務都須要使用這個轉換類。Token令牌默認是有簽名的,而且資源服務須要驗證這個簽名,所以呢,你須要使用一個對稱的Key值,用來參與簽名計算,這個Key值存在於受權服務以及資源服務之中。或者你可使用非對稱加密算法來對Token進行簽名,Public Key公佈在/oauth/token_key這個URL鏈接中,默認的訪問安全規則是"denyAll()",即在默認的狀況下它是關閉的,你能夠注入一個標準的 SpEL 表達式到 AuthorizationServerSecurityConfigurer 這個配置中來將它開啓(例如使用"permitAll()"來開啓可能比較合適,由於它是一個公共密鑰)。
 
若是你要使用 JwtTokenStore,請務必把"spring-security-jwt"這個依賴加入到你的classpath中。
 
 
配置受權類型(Grant Types):
受權是使用 AuthorizationEndpoint 這個端點來進行控制的,你可以使用 AuthorizationServerEndpointsConfigurer 這個對象的實例來進行配置(AuthorizationServerConfigurer 的一個回調配置項,見上的概述) ,若是你不進行設置的話,默認是除了資源全部者密碼(password)受權類型之外,支持其他全部標準受權類型的(RFC6749),咱們來看一下這個配置對象有哪些屬性能夠設置吧,以下列表:
  • authenticationManager:認證管理器,當你選擇了資源全部者密碼(password)受權類型的時候,請設置這個屬性注入一個 AuthenticationManager 對象。
  • userDetailsService:若是啊,你設置了這個屬性的話,那說明你有一個本身的 UserDetailsService 接口的實現,或者你能夠把這個東西設置到全局域上面去(例如 GlobalAuthenticationManagerConfigurer 這個配置對象),當你設置了這個以後,那麼 "refresh_token" 即刷新令牌受權類型模式的流程中就會包含一個檢查,用來確保這個帳號是否仍然有效,假如說你禁用了這個帳戶的話。
  • authorizationCodeServices:這個屬性是用來設置受權碼服務的(即 AuthorizationCodeServices 的實例對象),主要用於 "authorization_code" 受權碼類型模式。
  • implicitGrantService:這個屬性用於設置隱式受權模式,用來管理隱式受權模式的狀態。
  • tokenGranter:這個屬性就很牛B了,當你設置了這個東西(即 TokenGranter 接口實現),那麼受權將會交由你來徹底掌控,而且會忽略掉上面的這幾個屬性,這個屬性通常是用做拓展用途的,即標準的四種受權模式已經知足不了你的需求的時候,纔會考慮使用這個。
 
在XML配置中呢,你可使用 "authorization-server" 這個標籤元素來進行設置。
 
 
配置受權端點的URL(Endpoint URLs):
AuthorizationServerEndpointsConfigurer 這個配置對象(AuthorizationServerConfigurer 的一個回調配置項,見上的概述) 有一個叫作 pathMapping() 的方法用來配置端點URL連接,它有兩個參數:
  • 第一個參數:String 類型的,這個端點URL的默認連接。
  • 第二個參數:String 類型的,你要進行替代的URL連接。
以上的參數都將以 "/" 字符爲開始的字符串,框架的默認URL連接以下列表,能夠做爲這個 pathMapping() 方法的第一個參數:
  • /oauth/authorize:受權端點。
  • /oauth/token:令牌端點。
  • /oauth/confirm_access:用戶確認受權提交端點。
  • /oauth/error:受權服務錯誤信息端點。
  • /oauth/check_token:用於資源服務訪問的令牌解析端點。
  • /oauth/token_key:提供公有密匙的端點,若是你使用JWT令牌的話。
 
須要注意的是受權端點這個URL應該被Spring Security保護起來只供受權用戶訪問,咱們來看看在標準的Spring Security中 WebSecurityConfigurer 是怎麼用的。
 
@Override
protected void configure(HttpSecurity http) throws Exception {
    http .authorizeRequests().antMatchers("/login").permitAll().and()
    // default protection for all resources (including /oauth/authorize)
    .authorizeRequests() .anyRequest().hasRole("USER")
    // ... more configuration, e.g. for form login
}
注意:若是你的應用程序中既包含受權服務又包含資源服務的話,那麼這裏其實是另外一個的低優先級的過濾器來控制資源接口的,這些接口是被保護在了一個訪問令牌(access token)中,因此請挑選一個URL連接來確保你的資源接口中有一個不須要被保護的連接用來取得受權,就如上面示例中的 /login 連接,你須要在 WebSecurityConfigurer 配置對象中進行設置。
 
令牌端點默認也是受保護的,不過這裏使用的是基於 HTTP Basic Authentication 標準的驗證方式來驗證客戶端的,這在XML配置中是沒法進行設置的(因此它應該被明確的保護)。
 
在XML配置中可使用 <authorization-server/> 元素標籤來改變默認的端點URLs,注意在配置 /check_token 這個連接端點的時候,使用 check-token-enabled 屬性標記啓用。
 
 
強制使用SSL(Enforcing SSL):
使用簡單的HTTP請求來進行測試是能夠的,可是若是你要部署到產品環境上的時候,你應該永遠都使用SSL來保護受權服務器在與客戶端進行通信的時候進行加密。你能夠把受權服務應用程序放到一個安全的運行容器中,或者你可使用一個代理,若是你設置正確了的話它們應該工做的很好(這樣的話你就不須要設置任何東西了)。
可是也許你可能但願使用 Spring Security 的 requiresChannel() 約束來保證安全,對於受權端點來講(還記得上面的列表嗎,就是那個 /authorize 端點),它應該成爲應用程序安全鏈接的一部分,而對於 /token 令牌端點來講的話,它應該有一個標記被配置在 AuthorizationServerEndpointsConfigurer 配置對象中,你可使用 sslOnly() 方法來進行設置。固然了,這兩個設置是可選的,不過在以上兩種狀況中,會致使Spring Security 會把不安全的請求通道重定向到一個安全通道中。(譯者注:即將HTTP請求重定向到HTTPS請求上)。
 
 
自定義錯誤處理(Error Handling):
端點實際上就是一個特殊的Controller,它用於返回一些對象數據。
受權服務的錯誤信息是使用標準的Spring MVC來進行處理的,也就是 @ExceptionHandler 註解的端點方法,你也能夠提供一個 WebResponseExceptionTranslator 對象。最好的方式是改變響應的內容而不是直接進行渲染。
假如說在呈現令牌端點的時候發生了異常,那麼異常委託了 HttpMessageConverters 對象(它可以被添加到MVC配置中)來進行輸出。假如說在呈現受權端點的時候未經過驗證,則會被重定向到 /oauth/error 即錯誤信息端點中。whitelabel error (即Spring框架提供的一個默認錯誤頁面)錯誤端點提供了HTML的響應,可是你大概可能須要實現一個自定義錯誤頁面(例如只是簡單的增長一個 @Controller 映射到請求路徑上 @RequestMapping("/oauth/error"))。
 
 
映射用戶角色到權限範圍(Mapping User Roles to Scopes):
有時候限制令牌的權限範圍是頗有用的,這不只僅是針對於客戶端,你還能夠根據用戶的權限來進行限制。若是你使用 DefaultOAuth2RequestFactory 來配置 AuthorizationEndpoint 的話你能夠設置一個flag即 checkUserScopes=true來限制權限範圍,不過這隻能匹配到用戶的角色。你也能夠注入一個 OAuth2RequestFactory 到 TokenEnpoint 中,不過這隻能工做在 password 受權模式下。若是你安裝一個 TokenEndpointAuthenticationFilter 的話,你只須要增長一個過濾器到 HTTP BasicAuthenticationFilter 後面便可。固然了,你也能夠實現你本身的權限規則到 scopes 範圍的映射和安裝一個你本身版本的 OAuth2RequestFactory。AuthorizationServerEndpointConfigurer 配置對象容許你注入一個你自定義的 OAuth2RequestFactory,所以你可使用這個特性來設置這個工廠對象,前提是你使用 @EnableAuthorizationServer 註解來進行配置(見上面介紹的受權服務配置)。
 
 
 
2、資源服務配置:

一個資源服務(能夠和受權服務在同一個應用中,固然也能夠分離開成爲兩個不一樣的應用程序)提供一些受token令牌保護的資源,Spring OAuth提供者是經過Spring Security authentication filter 即驗證過濾器來實現的保護,你能夠經過 @EnableResourceServer 註解到一個 @Configuration 配置類上,而且必須使用 ResourceServerConfigurer 這個配置對象來進行配置(能夠選擇繼承自 ResourceServerConfigurerAdapter 而後覆寫其中的方法,參數就是這個對象的實例),下面是一些能夠配置的屬性:
  • tokenServices:ResourceServerTokenServices 類的實例,用來實現令牌服務。
  • resourceId:這個資源服務的ID,這個屬性是可選的,可是推薦設置並在受權服務中進行驗證。
  • 其餘的拓展屬性例如 tokenExtractor 令牌提取器用來提取請求中的令牌。
  • 請求匹配器,用來設置須要進行保護的資源路徑,默認的狀況下是受保護資源服務的所有路徑。
  • 受保護資源的訪問規則,默認的規則是簡單的身份驗證(plain authenticated)。
  • 其餘的自定義權限保護規則經過 HttpSecurity 來進行配置。
 
@EnableResourceServer 註解自動增長了一個類型爲 OAuth2AuthenticationProcessingFilter 的過濾器鏈,
 
在XML配置中,使用 <resource-server />標籤元素並指定id爲一個servlet過濾器就可以手動增長一個標準的過濾器鏈。
 
ResourceServerTokenServices 是組成受權服務的另外一半,若是你的受權服務和資源服務在同一個應用程序上的話,你可使用 DefaultTokenServices ,這樣的話,你就不用考慮關於實現全部必要的接口的一致性問題,這一般是很困難的。若是你的資源服務器是分離開的,那麼你就必需要確保可以有匹配受權服務提供的 ResourceServerTokenServices,它知道如何對令牌進行解碼。
在受權服務器上,你一般可使用 DefaultTokenServices 而且選擇一些主要的表達式經過 TokenStore(後端存儲或者本地編碼)。
RemoteTokenServices 能夠做爲一個替代,它將容許資源服務器經過HTTP請求來解碼令牌(也就是受權服務的 /oauth/check_token 端點)。若是你的資源服務沒有太大的訪問量的話,那麼使用RemoteTokenServices 將會很方便(全部受保護的資源請求都將請求一次受權服務用以檢驗token值),或者你能夠經過緩存來保存每個token驗證的結果。
使用受權服務的 /oauth/check_token 端點你須要將這個端點暴露出去,以便資源服務能夠進行訪問,這在我們受權服務配置中已經提到了,下面是一個例子:
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess(
"hasAuthority('ROLE_TRUSTED_CLIENT')"); }

 

在這個例子中,咱們配置了 /oauth/check_token 和 /oauth/token_key 這兩個端點(受信任的資源服務可以獲取到公有密匙,這是爲了驗證JWT令牌)。這兩個端點使用了HTTP Basic Authentication 即HTTP基自己份驗證,使用 client_credentials 受權模式能夠作到這一點。
 
 
配置OAuth-Aware表達式處理器(OAuth-Aware Expression Handler):
你也許但願使用 Spring Security's expression-based access control 來得到一些優點,一個表達式處理器會被註冊到默認的 @EnableResourceServer 配置中,這個表達式包含了 #oauth2.clientHasRole,#oauth2.clientHasAnyRole 以及 #oauth2.denyClient 所提供的方法來幫助你使用權限角色相關的功能(在 OAuth2SecurityExpressionMethods 中有完整的列表)。
在XML配置中你能夠註冊一個 OAuth-Aware 表達式處理器即 <expression-handler />元素標籤到 常規的 <http /> 安全配置上。
相關文章
相關標籤/搜索