一文看懂-深入淺出OAuth2.0授權


一、前言

說到OAuth,先來一段百度到的比較官方的解釋:

OAUTH協議為用戶資源的授權提供了一個安全的、開放而又簡易的標准。與以往的授權方式不同之處是OAUTH的授權不會使第三方觸及到用戶的帳號信息(如用戶名與密碼),即第三方無需使用用戶的用戶名與密碼就可以申請獲得該用戶資源的授權,因此OAUTH是安全的。OAuth是Open Authorization的簡寫。

說實話,每次見到官方定義的東西 都想

(╯' - ')╯︵ ┻━┻ (掀桌子) ┬─┬ ノ( ' - 'ノ) {擺好擺好) (╯°Д°)╯︵ ┻━┻(再掀一次)

單從字面意思來講,就是Open Authorization,即 開放 授權的意思。官方解釋就是官方,看了幾遍仍然不知道是什么東西,所以今天博主也根據自己的理解,完全用白話的方式,不摻雜一點官方語言來解釋下OAuth2.0。用你的親身經歷舉個栗子來說 就是  現在你用到的第三方登錄,比如qq、微信、微博登錄啊,免去了自己注冊賬號的煩惱,實際上這就是OAuth的實現和解決的問題。OAuth也經歷了幾個版本,目前到了2.0版本,也就是我們常說的OAuth2.0。

二、為什么要有OAuth

是為了解決問題啊(這不是廢話嗎,出來一個東西,肯定是要解決問題的),但是到底解決什么問題呢,再舉個栗子,不夠吃了。

2.1 解決用戶身份認證問題

我們每當去訪問一個網站的資源的時候,網站都會要求我們注冊一個賬號,訪問資源的時候登錄賬號來表名我們的身份,注意,這一步僅僅就是為了表名你的身份,知道你是個正常的人,而不是一些機器什么的。你對網站有什么操作,網站也能很好地監測到。

這樣一來,你每當去訪問一個新的網站的時候都要注冊賬號,對用戶來說,麻煩,反正我是不想注冊了,對網站來說,我得記錄你的賬號密碼什么的,也麻煩。(網站主要目的還是為了確定你的身份)。

那么問題來,能不能有一種方式,幫網站做認證來表名你是個正常的人,比如可以找一些比較出名且有權威的大公司大網站來認證一下,如qq,微博什么的,因為這些大公司已經存儲了你的身份,如果你訪問我的網站可以讓大公司來證明一下你的身份,我知道

你是誰就可以了,也不用你在我的網站注冊賬號了。這樣一來,你方便,我也方便。所以,OAuth2.0 給出了規范,來解決認證問題。

2.2 解決第三方網站訪問已有的用戶資源的問題

現在有這么一種情況,既然前邊已經說了,你可以用你的qq,微博賬號登錄我的網站,那么我又有其他非分之想了,我想獲取到你在qq或者微博上昵稱啊來顯示到我的網站上,這樣感覺高大上一點,更有甚者,我還想要。。。。emmm ,不是那個了。

我還想要其他東西,我想讀取下你的微博,說說啊什么的,或者我也想你能在我的網站發表這些東西。這樣豈不是更加高大上。但是這些功能都是qq和微博提供的,我怎么能獲取到權限呢。

 一個辦法就是 你把你的qq或者微博的賬號和密碼給我,我去登錄,這樣我就能像你一樣操作各種東西。但是你可能就不願意了,我的賬號密碼都給你了,萬一你把我上邊的小片什么的都泄漏出來,我還怎么才朋友里邊做人,萬一你裝作我搞一些壞事情,我豈不是更要身敗名裂,畢竟這是最高權限啊。還有,我這qq密碼說不定就是其他各種賬號的密碼,你給我存起來,登錄我的支付寶什么的,那怎么行。反正,就是一大堆不行。但是我要獲取你qq和微博上的東西你總得給我吧,所以為了解決這個問題。OAuth就又出來了,給出來規范,來解決資源授權問題。

 

三、OAuth解決上述問題的流程

很明顯,解決上述問題,需要三個人的參與,所以每個角色之間都得存守一定的約定和規則,這一套規則就是OAuth2.0協議的規范,具體比較官方的規范大家自己去看,本文就是以白話文的方式來講解的,不會有那種官方的條條框框。    

3.1 第三網站a與qq的協議(只以qq舉例子,其他都一樣)

首先qq會對他上邊的用戶權限進行分類,比如說獲取頭像,獲取昵稱,修改昵稱,讀取說說,發表說說之類的權限,都會進行整理,當a網站要獲取那些用戶的權限的時候就會頒發給他相應的權限,當然為了確定是a網站來訪問我大企鵝用戶的東西,會要求a網站在qq平台上注冊一下身份,比如說用client_idclient_sercret來表名a網站應用的身份,如果是b網站 想訪問也要注冊一下,將來qq也會知道是b網站來訪問我的用戶上的資源和權限。

當然,為了更加明確和安全,qq還會要求a網站注冊一個地址(redirect_url)或者注冊你需要獲取用戶的那些權限,這樣一來,你來的時候,我的檢查一下redirect_uri是不是你的,當你讓qq的用戶登錄授權成功之后,我也好根據redirect_url跳回去找你啊。

3.2 用戶和qq的協議 

用戶來進入a網站,a網站集成了“用qq登錄“登錄的功能,於是用戶點擊用qq登錄,那么a網站就會帶上client_id去跳轉到qq的授權頁面,qq一看client_id就知道是a網站來的,核對一下(通過client_id)這個a網站是qq授權過的客戶端,我根據client_id找出a網站可以獲取的權限,給用戶顯示出來,然后讓用戶選擇你是否同意a網站獲取你的這些權限。如下圖,這里我以碼雲 的qq登錄為例

我們可以看一下這個頁面的地址:https://graph.qq.com/oauth2.0/show?client_id=101284669&redirect_uri=https%3A%2F%2Fgitee.com%2Fauth%2Fqq_connect%2Fcallback&response_type=code&state=f70af08d82d762a56d844e0b0f1d0b7abafd48127c5b4ee0

1. 紅色部分是qq的授權地址,綠色部分是碼雲攜帶的參數,很明顯碼雲也向qq注冊了,有client_idredirect_uri兩個重要參數,redirect_uri用戶同意授權后跳回去,明顯是碼雲的一個地址。

2. response_type=code 這個參數是OAuth2.0規范,意識是授權方式為code方式,此處一般填寫固定值code,因為還有其他授權方式,但是不常用,

3. state=f70af08d82d762a56d844e0b0f1d0b7abafd48127c5b4ee0 這個也是里邊的規范 狀態參數 值是一個隨機字符串,需要qq原樣返回給碼雲的,置於什么作用,參考好多資料,都沒有明確指出,大家也只是遵守這個規范(不過肯定有用的,現在還不清楚)

注意:當用戶沒有同意,OAuth的授權流程就結束了。如果同意了,才繼續進行。

所以這一步流程就本就是,你帶着參數向qq的授權頁面跳轉 https://graph.qq.com/oauth2.0/show?&client_id=xxxx&redirect_uri=xxxxx&response_type=code&state=xxxx    紅色部分是你需要填寫的部分。大家可以參看微信網頁授權就是醬紫的。

3.3  qq的處理並且返回給a網站

qq肯定是作記錄啊,記錄用戶對碼雲授予了這兩個權限,將來出什么問題也好做一個憑證啊,萬一你來訛qq一下說,我沒有授權,你怎么把我的東西給碼雲了。(馬雲:管我什么事!!)記錄之后,會生成一個code碼,這個code肯定是和用戶的授權記錄是一一對應的,這個code碼也是OAuth2.0的規范,並且這個code碼有過期時間,並且只能用一次(置於為什么這么設計,先插個眼我們后邊說)。然后大家可以看后續的流程:

3.3.1 首先,qq會給我發個提示:說我已經授權了,表名qq已經知道了,並且也已經留取證據了,你就不可能反咬qq一口了,這也是OAuth2.0設置這一步的目的所在。整個三個角色的態度都會有記錄。

3.3.2 網址如下:https://gitee.com/auth/qq_connect/callback?code=FA0E3CBB6B699D894EE2BFD85691A561&state=f70af08d82d762a56d844e0b0f1d0b7abafd48127c5b4ee0  很明顯可以看到,這個地址是之前碼雲填寫的redirect_uri的地址,這里qq跳轉回來,並攜帶上了code碼,說明用戶已經同意了你的授權,至於state可以看見還是原樣返回的。

3.4 用code獲取access_token

上一步中,碼雲已經獲取到了code碼,但這個 code 只能表明,用戶允許碼雲從 qq上獲取該用戶的數據,如果我直接拿這個 code 去 qq訪問數據一定會被拒絕,因為任何人都可以持有 code,qq並不知道 code 持有方就是碼雲。

所以換取access_token的時候就要碼雲自己也攜帶着自己向qq申請的賬號密碼來換取了,這里邊已經在界面上看不到了,是再跳轉的過程中默默進行的。 

  POST https://www.oauth.qq.com/login/oauth/access_token //去請求qq獲取access_token的地址 一般都是post
  params = {
     code: "xxx",
     client_id: "xxx",
     client_secret: "xxx",
     redirect_uri: "https://gitee.com/auth/qq_connect/callback"
  }

當然如果一切正常,qq會給你返回如下結果

response = {
   access_token: "e72e16c7e42f292c6912e7710c838347ae178b4a"
   scope: "username,headimg" //這個是可以獲取用戶的權限的范圍,是前邊用戶選擇的部分,這里舉個例子,表示只允許獲取用戶名和頭像
   token_type: "bearer",
   refresh_token: "e72e1dedfs42f2923112e7710csafgsdaklfhalrf1352371537838347ae178b4a"
}

3.5 拿着access_token去調用接口

有access_token了還不為所欲為啊,獲取個昵稱,獲取的頭像,沒事發個說說,讀個微博啥的。到此OAuth2.0 授權流程基本就結束了。當然這個access_token也是有時間的,一般為兩個小時。過期的話用返回的refresh_token刷新,因為在請求接口的過程中傳輸的是access_token且只有兩小時的有效時間,即使是被別人截獲了,損失也不會太大,設計兩個小時的過期是為了安全考慮的。因為這一步的access_token是訪問接口的唯一憑據,並不會判斷調用者的來源。所以是有可能被非法者截獲搞出一些事情的。

四、總結

1.關於code碼的問題:

Q:為什么不直接發放access_token而非要返回一個code碼,然后用code換取access_token,這不是多次一舉嗎?

A:首先有這個想法很好,證明你是一個有思想的同學。當初我也想了好半天。因為qq根據要跳回你的網站才行,而跳轉到你的網站是302重定向,只能是get請求,所以要傳遞給碼雲一些數據信息的時候必須在url中添加參數,如果這時直接把access_token傳遞回來,就會暴露出來,這樣就很不安全,而且是依賴瀏覽器的,所以加了一部分,只把code碼傳回來,這樣即使code被暴露了也沒問題,因為碼雲要在再次用code碼和你的client_id,client_secret來請求qq,qq會做驗證,而這一步就可以不依賴瀏覽器了,你可以在服務器用代碼模擬http請求獲取acess_token,這樣就比較安全了。

Q:為什么code要設計成一次性的?

A:倘若code能無限次用,那么當用戶在上述情況下收回了權限,但是由於code還能用,本身code又關聯了用戶的授權信息,所以碼雲可能再次用code來換取token,這一步並沒有經過用戶的允許是違法的。所以不能讓code繼續使用。一次code表名了用戶的一次意願,並不是終生的意願。置於code為什么要設置有效期,我想應該是你如果獲取了code不使用,qq也不會說一直幫你存着吧。

另外,當授權碼發放之后,qq肯定也肯定添加並記錄了用戶當前對哪個網站發放了授權,這個記錄也為后來的用戶收回權限做准備,如果用戶要收回權限,直接對相關記錄操作就行。如下,是qq的授權管理:

 

2.關於OAuth的標准協議

有關OAuth的標准協議,各大廠商的內部實現可能不盡相同,有時候傳的參數多多少少會有一點出入,但是大體流程上都是這樣,而且有些必須參數都是一樣的。

協議的官方內容可以參考阮一峰老師的 理解OAuth 2.0。另一篇  簡述 OAuth 2.0 的運作流程 也很不錯。 


免責聲明!

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



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