基於實踐說規範
網上看了一些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