基於實踐說規范
網上看了一些OAuth 2.0的授權方法,盡管講解的沒有什么邏輯性錯誤,但是存在一個問題,那就是單純的講解協議規范卻脫離了實際的應用,缺少干貨,所以才有了這篇文章,內容基於實際業務進行講解,力求基於實踐說規范
OAuth 2.0
OAuth 引入了一個授權層,用來分離兩種不同的角色:客戶端和資源所有者。......資源所有者同意以后,資源服務器可以向客戶端頒發令牌。客戶端通過令牌,去請求數據。
OAuth 2.0 規定了四種獲得令牌的流程。你可以選擇最適合自己的那一種,向第三方應用頒發令牌。下面就是這四種授權方式。
授權碼(authorization-code) 隱藏式(implicit) 密碼式(password) 客戶端憑證(client credentials)
分類解讀
下面針對每一種進行詳細的解讀
授權碼(authorization code)
該類型的授權最為常見也是最安全的授權方式,指的是第三方應用先申請一個授權碼,然后再用該碼獲取令牌,微信、支付寶等大的開放平台使用的基本都是這種方式。
案例講解:A網站要實現微信用戶的授權登錄功能,首先A需要在微信公眾平台注冊一個應用,一般需要填寫應用圖標、名稱、回調鏈接等信息(有些平台需要上傳對應的非對稱加密的公鑰用於訪問的非對稱加密),審核通過后平台為該應用分配對應的參數一般包括:appId,appsecret等信息。
A網站開發人員拿到對應的信息后,需要攜帶appid、appsecret等信息訪問開放平台指定鏈接,例如:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECTURI&response_type=code&scope=SCOPE&state=STATE |


當用戶點擊授權后,平台會回調A網站在注冊應用時提供的回調地址(有些平台需要申請授權時實時的提供),並攜帶code碼(如有必要需要同時攜帶其他參數比如state參數),A網站拿到code碼后通過平台提供的sdk獲取openid、token、expired、refresh_oken、refesh_time等信息(code為參數調用開放平台接口獲取參數)
用戶拿到openid和token(令牌)就可以調用開放平台提供的服務了,到此,一個標准的授權碼授權流程就結束了。需要知道的是token是有有效期的,適用方需要指定token刷新策略,通過refresh_oken調用刷新接口獲取最新的token;
思考:為什么開放平台回調的時候是返回code,而不是直接返回token、openid等信息
- 直接返回token時涉及到跳轉本身就是明文,可能被篡改的問題,需要協定復雜的簽名協議來保證安全,這和 OAuth2 希望設計簡潔驗證模式的初衷違背;
- 一般情況下code是用后即失效並且時效較短,無法重復使用和超時使用,但是token的有效期較長,並且能重復使用,某個用戶對應的openid對A網站來說是唯一的,不會發生變化;
- 要想獲取token值需要提供appsecret作為參數(由第三方后端保存,不對外暴露),如果直接返回token,那么在頁面授權的時候需要將appsecret顯示的作為連接參數提供個開放平台,這顯然不合理;
隱藏式(implicit)
有些 Web 應用是純前端應用,沒有后端。這時就不能用上面的方式了,必須將令牌儲存在前端。RFC 6749 就規定了第二種方式,允許直接向前端頒發令牌。這種方式沒有授權碼這個中間步驟,所以稱為(授權碼)"隱藏式"(implicit)。
隱藏式授權的流程相對簡單,但安全性不高,所以只能用於以下安全性要求不高的場景,其基本步驟如下:
第一步,A 網站提供一個鏈接,要求用戶跳轉到 B 網站,授權用戶數據給 A 網站使用,如下:
https://b.com/oauth2/authorize?res_type=token& client_id=CLIENT_ID& . redirect_uri=CALLBACK_URL& scope=read
上面的url中res_type=token,標示返回的參數為token,也可以用其他的約定形式例如(authtype=implicit)
第二步,用戶跳轉到 B 網站,登錄后同意給予 A 網站授權。這時,B 網站就會跳回redirect_uri
參數指定的跳轉網址,並且把令牌作為 URL 參數,傳給 A 網站。
https://a.com/callback#token=ACCESS_TOKEN
注意,令牌的位置是 URL 錨點(fragment),而不是查詢參數,這是因為 OAuth 2.0 允許跳轉網址是 HTTP 協議,因此存在"中間人攻擊"的風險,而瀏覽器跳轉時,錨點不會發到服務器,就減少了泄漏令牌的風險。
關於token有效期的問題,一般采用隱藏式授權的的引用的有效期一般定為會話期間,隨着瀏覽器關閉,令牌隨之失效。一般不涉及到令牌的刷新問題(授權碼授權需要定期的更新令牌)
密碼式(password)
如果你高度信任某個應用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應用。該應用就使用你的密碼,申請令牌,這種方式稱為"密碼式"(password)
tips:B驗證通過后不進行頁面跳轉而是把令牌放到json數據里面,最晚http回應的形式,返回對應的數據,個人認為這種形式要暴露自己的用戶名和密碼,風險性太大,因此只適用於其他授權方式無法采用的情況,不建議使用,現實實踐中一般情況下使用appkey+secret+solt+timstamp+body數據加密的形式代替這種授權方法
客戶端憑證(client credentials)
適用於沒有前端的應用,即:第三方應用直接將appid、secret等參數作為憑證,通過后台接口調用授權方接口,授權方驗證通過后直接返回對應的token信息
https://b.com/oauth/token? grant_type=refresh_token& client_id=CLIENT_ID& client_secret=CLIENT_SECRET& refresh_token=REFRESH_TOKEN
OAuth2.0僅僅是個協議或者說是個規范,本身沒有什么意義,它的意義在於為嘗試為某種授權場景提供思路和規范,在設計自己的授權協議或者對接某開放平台的時候,能夠思路清理的理解每一個步驟,並且做出正確的選擇,顯示時間中授權碼的形式經常遇到,另外三種暫未遇到過,一般都是帶有加密算法的變形應用(接口鑒權),小伙伴們要靈活掌握;在后面的文章中我會詳細講解接口鑒權的集中形式。
參考鏈接:http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html