OAuth2 授權碼模式


3. 授權碼模式

  示例代碼對應倉庫:

本小節,我們來學習授權碼模式(Authorization Code)

授權碼模式,是功能最完整、流程最嚴密的授權模式。它的特點就是通過客戶端的后台服務器,與授權務器進行互動。

  一般情況下,在有客戶端的情況下,我們與第三方平台常常采用這種方式。

 

 

 

  • (A)用戶訪問客戶端,后者將前者跳轉到到授權服務器。
  • (B)用戶選擇是否給予客戶端授權。
  • (C)假設用戶給予授權,授權服務器將跳轉到客戶端事先指定的"重定向 URI"(Redirection URI),同時附上一個授權碼
  • (D)客戶端收到授權碼,附上早先的"重定向 URI",向認證服務器申請令牌。這一步是在客戶端的后台的服務器上完成的,對用戶不可見。
  • (E)認證服務器核對了授權碼重定向 URI,確認無誤后,向客戶端發送訪問令牌

 

下面,我們來新建兩個項目,搭建一個授權碼模式的使用示例。如下圖所示:

 

 

 

 

package com.example.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 用戶認證 Manager
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    //配置使用的 AuthenticationManager 實現用戶認證的功能
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    //設置 /oauth/check_token 端點,通過認證后可訪問。
    //這里的認證,指的是使用 client-id + client-secret 進行的客戶端認證,不要和用戶認證混淆。
    //其中,/oauth/check_token 端點對應 CheckTokenEndpoint 類,用於校驗訪問令牌的有效性。
    //在客戶端訪問資源服務器時,會在請求中帶上訪問令牌。
    //在資源服務器收到客戶端的請求時,會使用請求中的訪問令牌,找授權服務器確認該訪問令牌的有效性。
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.checkTokenAccess("isAuthenticated()");
    }

    //進行 Client 客戶端的配置。
    //設置使用基於內存的 Client 存儲器。實際情況下,最好放入數據庫中,方便管理。
/*
*
* 創建一個 Client 配置。如果要繼續添加另外的 Client 配置,可以在 <4.3> 處使用 #and() 方法繼續拼接。
* 注意,這里的 .withClient("clientapp").secret("112233") 代碼段,就是 client-id 和 client-secret。
*補充知識:可能會有胖友會問,為什么要創建 Client 的 client-id 和 client-secret 呢?
*通過 client-id 編號和 client-secret,授權服務器可以知道調用的來源以及正確性。這樣,
*即使“壞人”拿到 Access Token ,但是沒有 client-id 編號和 client-secret,也不能和授權服務器發生有效的交互。
*/
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory() // <4.1>
                .withClient("clientapp").secret("112233") // <4.2> Client 賬號、密碼。
                .authorizedGrantTypes("authorization_code") // <4.2> 授權碼模式
                .redirectUris("http://127.0.0.1:9090/callback")
                .scopes("read_userinfo", "read_contacts") // <4.2> 可授權的 Scope
//                .and().withClient() // <4.3> 可以繼續配置新的 Client
        ;
    }

}

  

 

僅僅需要修改 OAuth2AuthorizationServerConfig 類,設置使用 "authorization_code" 授權碼模式,並設置回調地址。

  注意,這里設置的回調地址,稍后我們會在「3.2 搭建資源服務器」中實現。

 

3.1.1 簡單測試

  執行 AuthorizationServerApplication 啟動授權服務器。

① 使用瀏覽器,訪問 http://127.0.0.1:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://127.0.0.1:9090/callback&response_type=code&scope=read_userinfo 地址,獲取授權。請求參數說明如下:

  • client_id 參數,必傳,為我們在 OAuth2AuthorizationServer 中配置的 Client 的編號。
  • redirect_uri 參數,可選,回調地址。當然,如果 client_id 對應的 Client 未配置 redirectUris 屬性,會報錯。
  • response_type 參數,必傳,返回結果為 code 授權碼
  • scope 參數,可選,申請授權的 Scope 。如果多個,使用逗號分隔。
  • state 參數,可選,表示客戶端的當前狀態,可以指定任意值,授權服務器會原封不動地返回這個值。

  友情提示:state 參數,未在上述 URL 中體現出來。

 

因為我們並未登錄授權服務器,所以被攔截跳轉到登錄界面。如下圖所示:

 

 

 

② 輸入用戶的賬號密碼「yunai/1024」進行登錄。登錄完成后,進入授權界面。如下圖所示:

    和我們日常使用的騰訊 QQ、微信、微博等等三方登錄,是一模一樣的,除了丑了點,嘿嘿~

 

 

③ 選擇 scope.read_userinfo 為 Approve 允許,點擊「Authorize」按鈕,完成授權操作。瀏覽器自動重定向到 Redirection URI 地址,並且在 URI 上可以看到 code 授權碼。如下圖所示:

 

 

  友情提示:/oauth/authorize 對應 AuthorizationEndpoint 端點。

 

④ 因為我們暫時沒有啟動資源服務器,所以顯示無法訪問。這里,我們先使用 Postman 模擬請求 http://localhost:8080/oauth/token 地址,使用授權碼獲取到訪問令牌。如下圖所示:

 

 

 

 

 

 

 請求說明:

  • 通過 Basic Auth 的方式,填寫 client-id + client-secret 作為用戶名與密碼,實現 Client 客戶端有效性的認證。
  • 請求參數 grant_type 為 "authorization_code",表示使用授權碼模式
  • 請求參數 code,從授權服務器獲取到的授權碼
  • 請求參數 redirect_uri,Client 客戶端的 Redirection URI 地址。

注意,授權碼僅能使用一次,重復請求會報 Invalid authorization code: 錯誤。如下圖所示:

 

 

 

3.2 搭建資源服務器

復制 lab-68-demo02-resource-server 項目,主要是提供回調地址。如下圖所示:

 

 

① 新建 CallbackController 類,提供 /callback 回調地址。

② 在 OAuth2ResourceServerConfig 配置類中,設置 /callback 回調地址無需權限驗證,不然回調都跳轉不過來哈。

 

3.2.1 CallbackController

創建 CallbackController 類,提供 /callback 回調地址,在獲取到授權碼時,請求授權服務器,通過授權碼獲取訪問令牌。代碼如下:

@RestController
@RequestMapping("/")
public class CallbackController {

    @Autowired
    private OAuth2ClientProperties oauth2ClientProperties;

    @Value("${security.oauth2.access-token-uri}")
    private String accessTokenUri;

    @GetMapping("/callback")
    public OAuth2AccessToken login(@RequestParam("code") String code) {
        // 創建 AuthorizationCodeResourceDetails 對象
        AuthorizationCodeResourceDetails resourceDetails = new AuthorizationCodeResourceDetails();
        resourceDetails.setAccessTokenUri(accessTokenUri);
        resourceDetails.setClientId(oauth2ClientProperties.getClientId());
        resourceDetails.setClientSecret(oauth2ClientProperties.getClientSecret());
        // 創建 OAuth2RestTemplate 對象
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
        restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setAuthorizationCode(code); // <1> 設置 code
        restTemplate.getOAuth2ClientContext().getAccessTokenRequest().setPreservedState("http://127.0.0.1:9090/callback"); // <2> 通過這個方式,設置 redirect_uri 參數
        restTemplate.setAccessTokenProvider(new AuthorizationCodeAccessTokenProvider());
        // 獲取訪問令牌
        return restTemplate.getAccessToken();
    }

}

  

代碼比較簡單,還是使用 OAuth2RestTemplate 進行請求授權服務器,胖友自己瞅瞅哈。

需要注意的是 <1> 和 <2> 處,設置請求授權服務器需要的 code 和 redirect_uri 參數。

 

3.2.2 簡單測試

執行 ResourceServerApplication 啟動資源服務器。

重復「3.2.1 簡單測試」的過程,成功獲取到訪問令牌。如下圖所示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM