天天看點

使用OAuth2的SSO分析

使用OAuth2的SSO分析

1.浏覽器向UI伺服器點選觸發要求安全認證 

2.跳轉到授權伺服器擷取授權許可碼 

3.從授權伺服器帶授權許可碼跳回來 

4.UI伺服器向授權伺服器擷取AccessToken 

5.傳回AccessToken到UI伺服器 

6.發出/resource請求到UI伺服器 

7.UI伺服器将/resource請求轉發到Resource伺服器 

8.Resource伺服器要求安全驗證,于是直接從授權伺服器擷取認證授權資訊進行判斷後(最後會響應給UI伺服器,UI伺服器再響應給浏覽中器)

一.先建立OAuth2授權伺服器 

1.使用spring Initializrt生成初始項目,選使用spring boot 1.3.3生成maven項目,根據需要填寫group,artifact,依賴選Web和Security兩塊,點生成按鈕即可. 

2.加入OAuth2依賴到pom.xml

修改主類(這裡同時也作為資源伺服器)

同時修改servlet容器的port,contextPath,注冊一個測試使用者與用戶端,加入配置:application.properties

基于spring boot的security的session建立政策預設是STATELESS,至于幾個選項意義,可看

啟動授權伺服器後,可測試了: 

a.打開浏覽器輸入位址

送出請求,然後根據以上配置,輸入使用者名/密碼,點同意,擷取傳回的授權許可碼 

b.在Linux的bash或mac的terminal輸入 

回車擷取access token,其中fjRdsL替換上步擷取的授權許可碼.傳回結果類似如下: 

從傳回結果複制access_token,繼續: 

其中上面的8eded27d-b849-4473-8b2d-49ae49e17943是access_token,根據實際情況替換,第二個指令傳回結果類似如下: 

從結果來看,使用access token通路資源一切正常,說明授權伺服器沒問題.

二.再看分離的資源伺服器(改動也不少) 

不再使用Spring Session從Redis抽取認證授權資訊,而是使用ResourceServerTokenServices向授權伺服器發送請求擷取認證授權資訊.

因些沒用到Spring Session時可移除,同時application.properties

配置

security.oauth2.resource.userInfoUri

security.oauth2.resource.tokenInfoUri

中的一個,

主類修改如下:

最後運作主類的main方法,開始測試(授權伺服器前面啟動了,access_token也得到了),于是在使用curl指令: 

傳回結果類似如下: 

可借鑒的經驗,我在windows上開發,啟動資源伺服器,然後資源伺服器有配置

,這裡限制容器隻能是本機通路,

如果使用區域網路IP是不可以通路的,比如你在别人的機器或在一台虛拟的linux上使用curl都是不是通路的,注釋這行配置,這限制就解除. 

跟蹤下擷取認證授權的資訊過程: 

1.userInfoRestTemplate Bean的聲明在

2.使用前面配置的userInfoUri和上面的userInfoRestTemplate Bean在org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerTokenServicesConfiguration.

RemoteTokenServicesConfiguration.

UserInfoTokenServicesConfiguration#userInfoTokenServices

建立UserInfoTokenServices Bean. 

3.在org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer#configure添加了org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter 

4.當使用curl -H “Authorization: Bearer $TOKEN” 192.168.1.115:9000送出請求時,直到被OAuth2AuthenticationProcessingFilter攔截器處理, 

org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter

#doFilter{ 

Authentication authentication = tokenExtractor.extract(request);//抽取Token 

Authentication authResult = authenticationManager.authenticate(authentication);//還原解碼認證授權資訊 

org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager

#authenticate{ 

OAuth2Authentication auth = tokenServices.loadAuthentication(token);//這裡的tokenServices就是上面的UserInfoTokenServices Bean,就在這裡向授權伺服器送出請求. 

三.UI伺服器作為SSO的用戶端. 

1.同樣UI伺服器不需要Spring Session,認證如我們所期望的,交給授權伺服器,是以使用Spring Security OAuth2依賴替換Spring Session和Redis依賴

2.當然UI伺服器還是API網關的角色,是以不要移除@EnableZuulProxy

在UI伺服器主類加上@EnableOAuth2Sso,這個注解會幫我們完成跳轉到授權伺服器,當然要些配置application.yml

這裡将”/user”請求代理到授權伺服器 

3.繼續修改UI主類繼承WebSecurityConfigurerAdapter,重寫org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter

#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity) 

目的是為了修改@EnableOAuth2Sso引起的預設Filter鍊,預設是org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2SsoDefaultConfiguration

#configure,

這個類上面有@Conditional(NeedsWebSecurityCondition.class)意思應該是,沒有WebSecurityConfigurerAdapter才會去執行這個config,

因為繼承了這個類,是以此config不再執行. 

4.作為oauth2的用戶端,application.yml下面這幾項是少不了的

最後一項,因為也作為資源伺服器,是以也加上吧

spring aop預設一般都是使用jdk生成代理,前提是要有接口,cglib生成代理,目标類不能是final類,這是最基本的條件.

估計是那些restTemplate沒有實作接口,是以不得不在這裡使用cglib生成代理. 

5.其它的前端微小改變,這裡不贅述.把授權伺服器,分離的資源伺服器和這個UI伺服器都啟動.準備測試:http://localhost:8080/login 

a.經過security的攔截連結中的

org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.doFilter攔截,

觸發了attemptAuthentication方法

acquireAccessToken(context)去擷取token的時候觸發抛異常.

在org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider

#getRedirectForAuthorization處理發送的url,

最後這個UserRedirectRequiredException往上抛,

一直往上抛到org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter#doFilter

終于看到redirectUser(redirect, request, response);進行跳轉到授權伺服器去了.

授權伺服器跳回到UI伺服器原來的位址(帶回來授權許可碼),再次被OAuth2ClientAuthenticationProcessingFilter攔截發送擷取accessToken,

經org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport

#retrieveToken送出POST請求,擷取到傳回原來發請求處得到OAuth2AccessToken對象. 

在org.springframework.security.oauth2.client.OAuth2RestTemplate#acquireAccessToken使用oauth2Context.setAccessToken(accessToken);

對token進行儲存.有了accessToken,就可以從授權伺服器擷取使用者資訊了.

最後,當使用者點logout的時候,授權伺服器根本沒有退出(銷毀認證授權資訊)

http://blog.csdn.net/xiejx618/article/details/51039653