續·前一篇《OAuth 2.0》html
在OAuth 2.0中,provider角色事實上是把受權服務和資源服務分開,有時候它們也可能在同一個應用中,用Spring Security OAuth你能夠選擇把它們分紅兩個應用,固然多個資源服務能夠共享同一個受權服務。java
獲取token的請求由Spring MVC的控制端點處理,訪問受保護的資源由標準的Spring Security請求過濾器處理。git
(The requests for the tokens are handled by Spring MVC controller endpoints, and access to protected resources is handled by standard Spring Security request filters. )github
爲了實現OAuth 2.0受權服務器,在Spring Security的過濾器鏈中須要有如下端點:web
在OAuth 2.0的資源服務器中須要實現下列過濾器:spring
對於全部的OAuth 2.0 provider特性,最簡單的配置是用Spring OAuth @Configuration適配器。sql
只要你配置了受權服務器,那麼你應該考慮客戶端用於獲取access token的受權類型(例如,受權碼,用戶憑證,刷新token)。數據庫
服務器的配置是用來提供client detail服務和token服務的,而且能夠啓用或者禁用全局的某些機制。後端
每一個客戶端能夠配置不一樣的權限api
@EnableAuthorizationServer註解被用來配置受權服務器,也能夠和實現了AuthorizationServerConfigurer接口的任意被標記爲@Bean的Bean一塊兒來對受權服務器進行配置。
下列特性被委託給AuthorizationServerConfigurer:
一件重要的事情是,provider配置了將受權碼給OAuth客戶端的方式(PS:在受權碼類型受權過程當中)
OAuth客戶端經過將end-user(最終用戶)導向受權頁,用戶可用在此輸入他的憑證。以後,受權服務器攜帶受權碼經過重定向的方式將受權碼返回給客戶端。
The ClientDetailsServiceConfigurer (a callback from your AuthorizationServerConfigurer) can be used to define an in-memory or JDBC implementation of the client details service.
ClientDetailsServiceConfigurer可用使用client details service的兩種實現中的任意一種:in-memory 或者 JDBC
客戶端重要的屬性是:
客戶端details能夠在應用運行時被更新,經過直接訪問存儲(例如:若是用JdbcClientDetailsService的話能夠實時改變數據庫表中的數據)或者經過實現ClientDetailsManager接口(它們也都實現了ClientDetailsService接口)。
NOTE: the schema for the JDBC service is not packaged with the library (because there are too many variations you might like to use in practice), but there is an example you can start from in the test code in github.
注意:用於JDBC服務的數據庫schema並無打包到library中(由於你再實際使用的時候可能有諸多差別),可是這裏有一個例子你能夠參考一下。
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
1 -- used in tests that use HSQL 2 create table oauth_client_details ( 3 client_id VARCHAR(256) PRIMARY KEY, 4 resource_ids VARCHAR(256), 5 client_secret VARCHAR(256), 6 scope VARCHAR(256), 7 authorized_grant_types VARCHAR(256), 8 web_server_redirect_uri VARCHAR(256), 9 authorities VARCHAR(256), 10 access_token_validity INTEGER, 11 refresh_token_validity INTEGER, 12 additional_information VARCHAR(4096), 13 autoapprove VARCHAR(256) 14 ); 15 16 create table oauth_client_token ( 17 token_id VARCHAR(256), 18 token LONGVARBINARY, 19 authentication_id VARCHAR(256) PRIMARY KEY, 20 user_name VARCHAR(256), 21 client_id VARCHAR(256) 22 ); 23 24 create table oauth_access_token ( 25 token_id VARCHAR(256), 26 token LONGVARBINARY, 27 authentication_id VARCHAR(256) PRIMARY KEY, 28 user_name VARCHAR(256), 29 client_id VARCHAR(256), 30 authentication LONGVARBINARY, 31 refresh_token VARCHAR(256) 32 ); 33 34 create table oauth_refresh_token ( 35 token_id VARCHAR(256), 36 token LONGVARBINARY, 37 authentication LONGVARBINARY 38 ); 39 40 create table oauth_code ( 41 code VARCHAR(256), authentication LONGVARBINARY 42 ); 43 44 create table oauth_approvals ( 45 userId VARCHAR(256), 46 clientId VARCHAR(256), 47 scope VARCHAR(256), 48 status VARCHAR(10), 49 expiresAt TIMESTAMP, 50 lastModifiedAt TIMESTAMP 51 ); 52 53 54 -- customized oauth_client_details table 55 create table ClientDetails ( 56 appId VARCHAR(256) PRIMARY KEY, 57 resourceIds VARCHAR(256), 58 appSecret VARCHAR(256), 59 scope VARCHAR(256), 60 grantTypes VARCHAR(256), 61 redirectUrl VARCHAR(256), 62 authorities VARCHAR(256), 63 access_token_validity INTEGER, 64 refresh_token_validity INTEGER, 65 additionalInformation VARCHAR(4096), 66 autoApproveScopes VARCHAR(256) 67 );
AuthorizationServerTokenServices定義了管理OAuth 2.0 Token所必須的操做。請注意:
當你實現了AuthorizationServerTokenServices接口,你可能考慮用DefaultTokenServices。有許多內置的插件化的策略能夠用來改變access token的格式和存儲。
默認狀況下,用隨機值來生成token,而且用TokenService來處理全部(除了token持久化之外)事情。默認的存儲是in-memory實現,可是有其它的實現可使用。
注意:對於JDBC的schema沒有打包到library中,可是這兒有一個例子你能夠參考一下test code in github。確保用@EnableTransactionManagement來防止多個客戶端在同一行建立token。注意,示例中的schema都有明確地主鍵聲明,在併發環境中這是必須的。
爲了使用JWT Tokens,你須要在你的受權服務器中有一個JwtTokenStore。資源服務器也須要解碼這個token,因此JwtTokenStore有一個依賴JwtAccessTokenConverter,相同的實現須要被包含在受權服務器和資源服務器中。也就是說,受權服務器和資源服務器中都須要JwtTokenStore實現。默認狀況下,token是被簽名的,並且資源服務器必須可以校驗這個簽名,所以須要有相同的對稱key,或者須要公鑰來匹配受權服務器上的私鑰。公鑰被受權服務器暴露在/oauth/token_key端點,默認狀況下這個端點的訪問規則是"denyAll()"。你能夠用標準的SpEL表達式(例如:permitAll())到AuthorizationServerSecurityConfigurer來開放它。
爲了使用JwtTokenStore,在classpath下須要有"spring-security-jwt"
受權類型經過AuthorizationEndpoint來支持。默認狀況下,除了password之外,全部受權類型都支持。下面是受權類型的一些屬性:
AuthorizationServerEndpointsConfigurer有一個pathMapping()方法。它有兩個參數:
下面是框架提供的URL路徑:
受權端點/oauth/authorize應該被保護起來,以致於它只能被認證過的用戶訪問。下面是一個例子,用標準的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 }
注意:若是您的受權服務器同時也是一個資源服務器的話,那麼就有另外一個具備較低優先級的安全過濾器鏈來控制API資源。經過訪問令牌來保護這些請求,你須要它們的路徑不能與主用戶過濾器鏈中的那些相匹配,因此請確保包含一個請求matcher,它只挑選出上面的WebSecurityConfigurer中的非api資源。
受權服務器的大多數端點主要都是被機器使用的,可是有兩個資源是須要UI,它們分別是/oauth/confirm_access和HTML響應/oauth/error。框架爲它們提供的實現是空白頁,真實的狀況是大多數受權服務器可能想要提供它們本身的實現來控制樣式和內容。因此,你須要作的事情就是提供一個Spring MVC 被標註了@RequestMappings註解的Controller來映射這些端點,而且框架將用一個低的優先級來發放請求。在默認的/oauth/confirm_access你指望一個AuthorizationRequest綁定到session。你能夠抓取請求的全部數據並按照本身喜歡的方式渲染它們,而後用戶須要作的就是向/oauth/authorize發送關於批准或拒絕授予的信息。默認的UserApprovalHandler取決因而否你再AuthorizationServerEndpointsConfigurer中提供了一個ApprovalStore。標準的審批處理器以下:
純HTTP對於測試來講是能夠的,可是在生成中受權服務器應該使用SSL。你能夠在一個安全的容器或代理後面運行應用程序,若是你正確地設置代理和容器(這與OAuth2無關),那麼它應該能夠正常工做。對於/authorize端點你須要把它看成正常的應用安全的一部分來作,對於/token端點在AuthorizationServerEndpointsConfigurer中有一個標記能夠設置,經過用sslOnly()方法。
受權服務器用標準的Spring MVC特性來進行錯誤處理。
你能夠提供本身的實現,經過添加@Controller而且帶上@RequestMapping("/oauth/error")
有時候,爲了限制token的scope,不只僅要根據指定的客戶端的範圍,也要根據用戶本身的權限來進行限制。若是你在你的AuthorizationEndpoint用DefaultOAuth2RequestFactory,你能夠設置checkUserScopes=true來限制匹配的用戶角色的容許範圍。AuthorizationServerEndpointsConfigurer容許你注入一個自定義的OAuth2RequestFactory
一個資源服務器(可能與受權服務器是相同的應用,也可能與受權服務器是分開的應用)經過OAuth2 Token服務受保護的資源。
Spring OAuth 提供一個Spring Security認證過濾器來實現這個保護。你能夠
你能夠在一個@Configuration類上用@EnableResourceServer來切換它,而且用ResourceServerConfigurer配置它。下列特性能夠被配置:
@EnableResourceServer註釋將自動添加一個OAuth2AuthenticationProcessingFilter類型的過濾器到Spring安全過濾器鏈中。
受保護的資源(或者叫遠程資源)能夠用OAuth2ProtectedResourceDetails類型的bean來定義。一個被保護的資源由下列屬性:
不一樣的受權類型有不一樣的OAuth2ProtectedResourceDetails的具體實現(例如:ClientCredentialsResourceDetails是"client_credentials"類型的具體實現)
對於OAuth 2.0客戶端配置,簡化的配置用@EnableOAuth2Client。這個註解作兩件事情:
AccessTokenRequest能夠用在一個OAuth2RestTemplate中,就像下面這樣:
@Autowired private OAuth2ClientContext oauth2Context; @Bean public OAuth2RestTemplate sparklrRestTemplate() { return new OAuth2RestTemplate(sparklr(), oauth2Context); }
建議用RestTemplate訪問受保護的資源。
Spring Security爲OAuth提供了一個擴展的RestTemplate只須要你提供一個OAuth2ProtectedResourceDetails的實例便可。爲了使它和用戶token(受權碼方式受權)一塊兒使用,你應該考慮用@EnableOAuth2Client配置。
通常來講,web應用程序不該該使用密碼授予,所以若是您能夠支持AuthorizationCodeResourceDetails,請避免使用ResourceOwnerPasswordResourceDetails。
爲了和用戶令牌(受權碼)一塊兒使用,你應該考慮用@EnableOAuth2Client配置。
客戶端不須要持久化令牌,可是最好不要在每次重啓客戶端應用程序時都要求用戶批准新的令牌授予。
ClientTokenServices接口定義了爲特定用戶保存OAuth 2.0令牌所需的操做。這是一個JDBC實現,可是若是您但願實現本身的服務,以便在持久數據庫中存儲訪問令牌和相關的身份驗證明例,則能夠這樣作。若是你想要使用這個特性,你須要爲OAuth2RestTemplate提供一個通過特殊配置的TokenProvider。例如:
@Bean @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES) public OAuth2RestOperations restTemplate() { OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(accessTokenRequest)); AccessTokenProviderChain provider = new AccessTokenProviderChain(Arrays.asList(new AuthorizationCodeAccessTokenProvider())); provider.setClientTokenServices(clientTokenServices()); return template; }
https://projects.spring.io/spring-security-oauth/docs/oauth2.html