OAuth2.0原理與實現


弄懂了原理流程,才可以搭建出來。更重要的是,可以根據原理流程自定義搭建,甚至可以完全自己實現一套,最后運行效果和原理和這個對得上就成功了,不要總期待標准答案!

首先參考兩篇博客:

阮一峰的博客以及張開濤的博客

圖分析補充:

第一步訪問授權頁面(然后授權服務器返回授權頁面)時,即需要預先申請的開發者信息如client_id、redirect_uri,而授權服務器在第三步用戶手動授權后才用到這些信息,進行頁面跳轉(response狀態碼302,附上redirect地址和授權碼等),第四步是第三部redirect_uri所指向的應用開發后台地址,是第三步的網頁自動重定向所訪問到的,這個后台邏輯要自己寫,內容是拼接redirect_uri和授權碼code參數,訪問認證服務器后台,申請令牌返回。這樣應用獲取到令牌,此后使用令牌繼續訪問資源服務器獲取資源進行使用,由此跳轉到自己的應用頁面(一般是一個綁定手機號頁面,使用微信賬號與之綁定,是一個注冊,把微信賬號access_token與手機號賬號綁定,存入應用自身數據庫,當然access_token存在有效期,過期后也需要在用戶再次登錄時在自身數據庫透明更新)

(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:表示客戶端的當前狀態,可以指定任意值,認證服務器會原封不動地返回這個值。

下面是一個例子。


GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
        &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com 

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

  • code:表示授權碼,必選項。該碼的有效期應該很短,通常設為10分鍾,客戶端只能使用該碼一次,否則會被授權服務器拒絕。該碼與客戶端ID和重定向URI,是一一對應關系。
  • state:如果客戶端的請求中包含這個參數,認證服務器的回應也必須一模一樣包含這個參數。

下面是一個例子。


HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA &state=xyz 

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

  • grant_type:表示使用的授權模式,必選項,此處的值固定為"authorization_code"。
  • code:表示上一步獲得的授權碼,必選項。
  • redirect_uri:表示重定向URI,必選項,且必須與A步驟中的該參數值保持一致。
  • client_id:表示客戶端ID,必選項。

下面是一個例子。


POST /token HTTP/1.1
Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb 

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

  • access_token:表示訪問令牌,必選項。
  • token_type:表示令牌類型,該值大小寫不敏感,必選項,可以是bearer類型或mac類型。
  • expires_in:表示過期時間,單位為秒。如果省略該參數,必須其他方式設置過期時間。
  • refresh_token:表示更新令牌,用來獲取下一次的訪問令牌,可選項。
  • scope:表示權限范圍,如果與客戶端申請的范圍一致,此項可省略。

下面是一個例子。


     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" } 

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

 

具體到應用開發上,無論是網站還是手機App,原理都是相同的:用戶訪問應用(比如微信登錄功能),應用(使用申請的開發者信息如client_id、redirect_uri)訪問資源服務器(微信后台,一個例子是很多App直接請求打開微信客戶端,那么必然是訪問微信后台),返回授權頁面(微信授權)。用戶輸入資源服務器用戶名/密碼(微信),或直接獲取已登錄賬號(比如手機App微信賬號),點擊授權(認證服務器驗證微信賬號信息)。授權后根據該應用此前傳遞的redirect_uri重定向到應用頁面並附上授權碼(code),應用使用重定向的網址和授權碼訪問應用自己的后台,由后台再不可見地使用redirect_uri、code到認證服務器獲取令牌(access_token,可選refresh_token)返回。

 

一個細節是返回授權頁面,傳統方式是應用內嵌一個微信用戶名/密碼登錄頁面(由微信后台返回),現在一般使用二維碼掃描方式。

一個例子是微信網頁版的微信授權登錄:

根據https://www.oschina.net/question/1172551_218058和親自追蹤,采用的是二維碼ajax輪詢方式:

“打開https://wx.qq.com/用FireFox看吧,它不斷輪詢https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?uuid=xxxx&tip=1&_=1419316260694

用微信一掃這個結果就變了。”

“ajax輪訓,前台每隔5秒訪問一次后台,如果返回1這跳轉,如果不是則繼續查詢

手機掃描二維碼實際上是訪問一個鏈接,當成功掃描,則把上一個鏈接返回1.這樣電腦端就可以跳轉了”

這個網頁(打開后)上的二維碼實際是不斷輪詢ajax訪問微信后台的:

微信掃碼后,微信后台一個字段改變(如此感知掃碼),應用會訪問到該微信用戶信息(比如圖片),等待授權,地址不跳轉(不變),同時會繼續輪詢此前輪詢的微信后台地址:

而掃碼后的手機端,最終訪問的是微信后台返回的授權頁面(實際帶上了應用的client_id、redirect_uri信息,經過了應用后台的轉發)。手機端點擊授權之后,微信后台有另一個特定標示字段的改變(數據庫或緩存),這樣網頁二維碼頁面的ajax長輪詢(無論的Comet技術還是WebSocket,均可立即推送這個字段值改變)就可訪問到這個改變的字段,根據微信后台授權邏輯,就可立即跳轉到授權后的頁面(redirect_uri):

這就是網頁自動跳轉的原理。其實后台透明地經歷了另一個獲取令牌的過程,讓網頁直接根據令牌訪問到了該微信用戶(資源服務器)的有限制資源(這里特殊,幾乎是該用戶的所有資源)。

 

App應用(區別於網站應用)的授權過程表現出請求手機系統(表現為出現彈出框讓用戶同意)訪問微信客戶端,使用微信客戶端(內嵌在App應用中,所以此時實際仍然在該App應用中進行操作,所以才有后來的跳轉回App應用申請完授權資源后的頁面)訪問微信后台,返回一個授權頁面(應用內訪問微信,實際仍然在應用頁面里)。用戶點擊授權后,自動跳轉到應用頁面(現在很多應用都有一個手機號綁定,短信驗證碼驗證后進行綁定的頁面,點擊后進入真正的應用頁面,一般是個人主頁)。其實后台經歷了一個獲取授權碼(authorization code)、重定向、獲取令牌(access token),再用令牌有限制訪問資源(仍然指微信賬號信息)的過程。

 

令牌(access token)一般有很短的有效期(2小時),需要使用refresh_token來定期刷新,refresh_token有效期較長(30天),失效后需要用戶重新授權。表現為退出登錄后再微信登錄,短期內不再需要用戶再手動進行微信授權,說明短期內(access token有效)仍然有權訪問該有限制資源(微信賬號信息)。

后台需要有用戶名/密碼認證、授權機制,保存令牌的數據庫或緩存,令牌生成接口,刷新令牌接口,過期自動刪除令牌機制(參考Spring SSO的JWT令牌配置和實現),資源服務權限配置,驗證令牌放行或拒絕資源訪問機制。搞清這套邏輯和技術實現原理,嘗試自定義實現或完全自主實現。

標准OAuth2.0系統參考:

微信公眾開發平台:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN

 


免責聲明!

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



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