天天看點

建立自己的OAuth2.0服務端

1. 前言

本篇文章時對 用戶端的授權模式-授權碼模式 的建立,當然你了解的最複雜的模式之後,其他模式都是在授權碼模式上面做一些小改動即可。對于授權碼模式有任何的疑問,請看上面提到的文章。

注意:本文是建立OAuth的Server端,不是Client請求端。

2. 開始授權碼模式的概念、流程

第2點其實就是複制了上一篇文章,為了提高閱讀性,讀過上一篇文章的可略過第2點。

授權碼模式(authorization code)是功能最完整、流程最嚴密的授權模式。它的特點就是通過用戶端的背景伺服器,與"服務提供商"的認證伺服器進行互動。

流程圖:

​​

建立自己的OAuth2.0服務端

圖說明:

  (A)使用者通路用戶端,後者将前者導向認證伺服器。

  (B)使用者選擇是否給予用戶端授權。

  (C)假設使用者給予授權,認證伺服器将使用者導向用戶端事先指定的"重定向URI"(redirection URI),同時附上一個授權碼。

  (D)用戶端收到授權碼,附上早先的"重定向URI",向認證伺服器申請令牌。這一步是在用戶端的背景的伺服器上完成的,對使用者不可見。

  (E)認證伺服器核對了授權碼和重定向URI,确認無誤後,向用戶端發送通路令牌(access token)和更新令牌(refresh token)。

下面是上面這些步驟所需要的參數。

A步驟中,用戶端申請認證的URI,包含以下參數:

response_type:表示授權類型,必選項,此處的值固定為"code"

client_id:表示用戶端的ID,必選項

redirect_uri:表示重定向URI,可選項

scope:表示申請的權限範圍,可選項

state:表示用戶端的目前狀态,可以指定任意值,認證伺服器會原封不動地傳回這個值。

例子:

C步驟中,伺服器回應用戶端的URI,包含以下參數:

code:表示授權碼,必選項。該碼的有效期應該很短,通常設為10分鐘,用戶端隻能使用該碼一次,否則會被授權伺服器拒絕。該碼與用戶端ID和重定向URI,是一一對應關系。

state:如果用戶端的請求中包含這個參數,認證伺服器的回應也必須一模一樣包含這個參數。

D步驟中,用戶端向認證伺服器申請令牌的HTTP請求,包含以下參數:

grant_type:表示使用的授權模式,必選項,此處的值固定為"authorization_code"。

code:表示上一步獲得的授權碼,必選項。

redirect_uri:表示重定向URI,必選項,且必須與A步驟中的該參數值保持一緻。

client_id:表示用戶端ID,必選項。

E步驟中,認證伺服器發送的HTTP回複,包含以下參數:

access_token:表示通路令牌,必選項。

token_type:表示令牌類型,該值大小寫不敏感,必選項,可以是bearer類型或mac類型。

expires_in:表示過期時間,機關為秒。如果省略該參數,必須其他方式設定過期時間。

refresh_token:表示更新令牌,用來擷取下一次的通路令牌,可選項。

scope:表示權限範圍,如果與用戶端申請的範圍一緻,此項可省略。

從上面代碼可以看到,相關參數使用JSON格式發送(Content-Type: application/json)。此外,HTTP頭資訊中明确指定不得緩存。

3. 開始寫自己的OAuth2.0服務端代碼(C#)

如果有錯誤的地方,歡迎指正,作者也不保證完全正确。

這裡介紹的是C#,當然你可以用你自己的語言寫,大同小異。(沒用到第三方關于OAuth2.0的架構)

作者在開始了解OAuth2.0的概念時,化了一段比較長的時間。從微信授權開始接觸OAuth2.0的概念,後來寫了一套第三方微信授權的小程式,慢慢消化OAuth2.0。

說實在的,OAuth2.0安全在于,提供了code、access_token,來綁定我們的使用者資訊。并且code、access_token有過期的時間。是以,關鍵在于了解code與access_token的作用。

開始代碼,我們建立一個MVC的程式,這裡叫做MyOAuth2Server。

3.1開始授權驗證

第一步,開始授權驗證,并且跳轉到指定的授權頁面。

先上代碼,然後再分析:

建立自己的OAuth2.0服務端

用戶端會授權會請求我們授權驗證方法,

     首先,驗證client_id是否可用,這裡的client_id是為了保證安全性,確定請求端是服務端給予請求或者授權的權利。簡單地說,就是請求端在用此服務端之前要申請唯一的一個client_id;

     然後,在把用戶端傳過來的資訊儲存在Session(你也可以儲存在其他地方);

     最後,跳轉到使用者操作的,是否給予授權的頁面(可以是點選一個确定授權的按鈕,類似于微信授權。也可以是輸入使用者名&密碼等的頁面)。

下面我們看一下 return View("Authorize"); 這句代碼所傳回給使用者許可的頁面:

從上面可以看到,使用者确定授權後會送出資訊到Authenticate方法,下面我們看看Authenticate到底是做了什麼。

3.2驗證并傳回code到請求端

我們這裡是使用者名與密碼驗證,當然你也可以用其他驗證。(比如使用者點選一個授權允許的按鈕就可以了)

     首先,在OAuth2.0服務端上驗證使用者輸入的使用者名與密碼是否正确;

     然後,生成code,并且設定code的生存時間,預設是30秒。(code隻能用一次,之後要删除);

     再綁定code與使用者資訊(使用者唯一鍵);

     最後,重定向回redirect_uri請求的位址,并且傳回code與state。(state是請求端那邊想要用于處理一些業務邏輯所用到的,當然可以為空)

上代碼

上面,已經完成了code的使命,并且傳回到了請求端。

下面,我們來看看怎麼擷取token。

3.3擷取token

在請求端擷取到code之後,請求端要擷取token,因為擷取了token請求端才能擷取到使用者資訊等資料。

     首先,把token設定成不能保持cache的狀态,為了保證安全性;

     然後,判斷是擷取token還是重新整理token的狀态;

     再驗證code是否過期,驗證client_id、client_secret是否正确;

     再生成token,把token存入容器(DB、Redis、Memory等)中;

     在通過code來擷取使用者的資訊,把使用者資訊(主鍵)與token做綁定;

     最後,把code删除(code隻能用一次,如果想再擷取token隻能第一步開始重新做),傳回token。

上代碼:

3.4通過token擷取使用者資訊

上面請求端已經擷取到了token,是以這裡隻需要驗證token,token驗證通過就直接傳回使用者資訊。

驗證token包括驗證是否存在、驗證是否過期。

4. 結語

到此,我們寫OAuth2.0服務端的代碼已經結束了。

在上一篇文章中,我們介紹了怎麼建立自己的伺服器,現在我們開始寫個client端,來測試。

我們建立一個MVC項目,叫TestOAuthClient

1. 代碼開始

1)第一步,我們建立一個MainController,在Index方法裡面寫我們的邏輯。

2)首先擷取code,如果沒有code,則證明是第一步請求。

3)第一步請求,附上client_id、response_type、redirect_uri、scope、state參數。

這裡我們假如服務端的第一步請求認證的位址為:​​http://localhost:65006/OAuth2Server/Authorize​​

     client_id是請求端在服務端申請的id;

     response_type為code;

     redirect_uri是告訴服務端,擷取code之後傳回的位址是什麼;

     scope自定義;

     state自定義。

4)跳轉到驗證伺服器。

5)驗證伺服器重定向會我們的請求端後(code不為空),請求擷取token。

擷取token需要傳送傳回的code、grant_type=authorization_code、client_id、client_secret

6)通過伺服器傳回的token,請求服務端擷取使用者資訊。

代碼就幾行,如下:

2. 開始調試

1)請求端(TestOAuthClient)的位址為:​​http://localhost:61481/Main/Index​​

2)在浏覽器上輸入上面位址,會重定向到使用者是否允許授權的頁面。(此頁面是服務端的頁面)

建立自己的OAuth2.0服務端

當我們輸入正确的使用者名&密碼之後,會發現,再請求端能擷取到使用者的資訊。

到此,測試結束。