OAuth 2.0一詞中的"Auth"表示"授權Authorization",字母"O"表示"開放Open",連在一起就表示"開放授權"。這也是為什麼我們使用OAuth的場景,通常發生在開放平臺的環境下。
OAuth 2.0提供了4種模式:
資源擁有者憑據許可(Resource Owner Password Credentials)
隱式許可(Implicit)
客戶端憑據許可(Client Credentials)
授權碼許可(Authorization Code)
本文將介紹OAuth2.0授權碼許可的模式,授權碼許可是應用最為廣泛的開放授權模式,比如微信開放平臺、阿里開放平臺等都是基於這個模式做開放授權。
開放授權出現的意義
我們首先需要區分下認證和授權:
認證(Authentication):用來驗證某個使用者是否具有訪問系統的許可權。如果認證透過,該使用者就可以訪問系統,從而建立、修改、刪除、查詢平臺支援的資源。認證的方式就是我們登入,比如賬密登入、手機驗證碼登入等。
授權(Authorization):用來驗證某個使用者是否具有訪問某個資源的許可權,如果授權透過,該使用者就能對資源做增刪改查等操作。
簡單而言,認證就是證明訪問者的身份,決定他是否能進入系統;授權則是決定訪問者能做哪些內容。一般來說,都是先認證後檢查授權。
OAuth 誕生之初是為了解決 Web 瀏覽器場景下的授權問題。比如有一個網站A,在新使用者註冊時是支援QQ賬號註冊的,如果網站A能拿到QQ暱稱和頭像作為網站A使用者註冊的基本資料,這樣新註冊使用者流程就簡單多了,很多資訊都不需要使用者自己填寫,直接套用QQ號的資訊就可以了。這樣的註冊模式就對使用者很友好,自然很容易提升使用者註冊的熱情。
這個【訪問使用者QQ頭像和暱稱】就涉及到授權問題了。我的QQ資訊為什麼可以給網站A使用?如果我同意網站A獲取我的QQ暱稱,那我的QQ空間的資訊網站A是否也可以訪問呢?這就涉及到授權範圍的內容了。開放授權是個很複雜的模式,需要一個安全且友好的機制來支援。
註冊時的開放授權和長期訪問QQ空間資訊的開發授權的複雜度時不一樣的。
註冊時授權獲取QQ暱稱等資訊是一次性的,需要考慮的事情可能沒那麼多,也許一個請求回覆就能拿到這些資訊了,以後不會再需要二次獲取。但如果網站A還有個業務,支援管理QQ空間裡的照片,此時需要向使用者申請授權:請允許網站A可以訪問你的QQ空間的照片。這種資源的訪問就不是一次性了,是反覆多次的訪問,這個就更為複雜,首先我們不可能網站A每一次訪問我們都點一次【同意授權】,如果我們當時沒有登陸QQ,還得先賬密登入QQ才可以進行授權。這樣對使用者體驗很不友好。因此需要一種安全便捷的方式去處理這種頻繁訪問受限資源的場景。這個就是開放授權出現的意義:把私有資源有限地開放給第三方訪問和使用,而且需要做到安全高效。OAuth 2.0能很好地解決了這個問題。
OAuth2.0 定義的角色型別
根據 OAuth 2.0 協議規範,OAuth 2.0體系下有四個角色型別:
授權伺服器,負責頒發 Access Token,比如微信開放平臺授權伺服器。
資源所有者,你的應用的使用者是資源的所有者,授權其他人訪問他的資源。比如微信使用者是資源所有者。
呼叫方,呼叫方請求獲取 Access Token,經過使用者授權後,微信開放平臺為其頒發 Access Token。呼叫方可以攜帶 Access Token 到資源伺服器訪問使用者的資源。比如呼叫方是上文說的網站A。
資源伺服器,接受 Access Token,然後驗證它的被賦予的許可權專案,最後返回資源。比如微信開放平臺資源伺服器。
接下來,我們將以微信使用者授權第三方網站A的案例,介紹OAuth2.0授權碼模式下的授權流程。
OAuth2.0授權碼模式流程
我們先看下業界標杆微信開放平臺是怎麼做開放授權的。網站應用微信登入是基於OAuth2.0協議標準構建的微信OAuth2.0授權登入系統,微信OAuth2.0授權登入目前支援authorization_code模式。
先上序列圖:
流程步驟:
網站A需要在微信開放平臺註冊,填寫回撥地址,並獲得相應的 AppID 和AppSecret。
使用者登入了網站A,獲得了網站A的登入態,這裡用JWT來維護登入態。
此時網站A需要訪問使用者的微信相關資源,這裡需要獲得使用者的微信授權。網站A彈出一個頁面引導使用者去微信開放平臺的網站來授權。
使用者點選【去授權】,瀏覽器跳轉到微信二維碼介面。
此時微信使用者尚未在web端登入,因此需要微信使用者【掃碼登入】,登入成功後瀏覽器帶著AppID請求微信開放平臺,請求授權給網站A。
微信開放平臺同意後返回頁面讓微信使用者確認:網站A將獲取以下許可權:1. ... 2. ...,是否同意授權。
點選【同意授權】,使用者瀏覽器就帶著AppID和重定向URI兩個引數去請求微信開放平臺的授權伺服器。重定向URI是網站A的地址。
微信開放平臺的授權伺服器收到請求,透過AppID知道了這個是要微信使用者要給網站A授權,因此生成了一個授權碼CODE,以重定向的方式返回給微信使用者,重定向的地址填的是第7步請求帶上來的URI,並引數帶上這個CODE。
微信使用者收到重定向的回覆後,拿出重定向URI和CODE,重定向跳轉到這個URI,並引數帶上這個CODE。因為跳轉的網址是網站A的域名地址,因為使用者已經在該網站登入了,因此這個請求會帶上登入態的JWT。
網站A收到微信使用者CODE後,從JWT中解析出這個請求的來源使用者的uid,這樣網站使用者uid就跟CODE有了繫結關係。接著拿出自己的AppID 和AppSecret,跟CODE一起請求微信開放平臺授權伺服器。
微信開放平臺授權伺服器收到AppID + AppSecre + CODE 三個引數後,生成access_token、refresh_token,返回這些token給網站A。
網站A拿到access_token後就儲存起來,有了uid->access_token的對映關係。後續帶著這個access_token就可以訪問微信使用者的指定資源了,無需每次要微信使用者登入和授權。
access_token和refresh_token的關係
access_token是呼叫授權關係介面的呼叫憑證,由於access_token有效期(目前為2個小時)較短,當access_token超時後,可以使用refresh_token進行重新整理,access_token重新整理結果有兩種:
若access_token已超時,那麼進行refresh_token會獲取一個新的access_token,新的超時時間;
若access_token未超時,那麼進行refresh_token不會改變access_token,但超時時間會重新整理,相當於續期access_token(注意,微信開放平臺是在原來的access_token上做延時,有的開放平臺是直接換一個新的access_token)。
refresh_token擁有較長的有效期(30天),當refresh_token失效後,需要使用者重新授權。
因為access_token是需要頻繁在網路上傳輸的,因此被竊取的風險大,所access_token的有效時間設定較短;refresh_token僅僅在續簽access_token時會在網路上傳輸,被竊取的風險相對小點,因此refresh_token擁有較長的有效期。這樣一長一短的雙token機制會比較安全。
雙Token機制更為安全,而且可以很好的處理線上、離線續簽的問題,可以參考這個回答深入理解雙Token機制。
jwt續簽為什麼要使用雙token,沒看明白啊,感覺單個token也可以啊? https://www.zhihu.com/question/506320859/answer/2913798899
47 贊同 · 19 評論回答
OAuth2.0授權碼模式困惑點
為什麼OAuth2裡面在獲取access token之前一定要先獲取code,然後再用code去獲取access token?
為什麼OAuth2裡面在獲取access token之前一定要先獲取code,然後再用code去獲取access token? https://www.zhihu.com/question/27446826/answer/2916005175
15 贊同 · 2 評論回答
Token的續簽是系統自動完成的嗎?
續簽是客戶端寫程式碼來實現自動更換的,比如客戶端本地週期檢查access_token是否即將過期或者已經過期,是的話就拿refresh_token去換新的access_token。
授權碼被盜取後,人家不能也模擬伺服器請求獲取access_token嗎?
首先授權碼有以下基本的安全措施:授權碼存在有效期,一般很短只有幾分鐘,過期了就沒法用了;授權碼只有一次使用機會,如果該授權碼已經被人兌換過了,後面就沒法兌換了。
如果是無appSecret的模式,授權碼被盜取後是有機會被模擬盜竊access_token的。
在appSecret這種模式下,兌換access token,如果只有授權碼是沒法兌換access token,還得有appSecret+授權碼來兌換。所以appSecret這種模式更為安全。
redirect_uri既然在註冊的時候已經填了,為什麼請求授權碼時還要再傳一遍這個引數?
因為註冊時可能會填了多個uri,因此帶引數redirect_uri請求時,授權伺服器會校驗是否該uri是否處於註冊的uri列表中。
參考連結:https://zhuanlan.zhihu.com/p/610490265?s_r=0