之前在討論 API 身分驗證時,已有小提一下 OAuth 2.0 授權框架(以下簡稱 OAuth2)的概觀了。
在開始講細節之前,先簡單說明一下身分驗證(authentication)、授權(authorization)與存取控制(access control)的差異,有些人(如筆者)很容易把這三者搞混。
存取控制如 ACL(access control list)或 RBAC(role-based access control)。
透過身分驗證,可以讓系統知道目前的使用者是哪個實體。
如:輸入 root 帳號密碼成功,可以知道現在進來的使用者,是 Linux 裡所定義的超級使用者(super user)。
在 OAuth2 的世界裡,授權指的是使用者,讓第三方應用程式取得使用者的資源。
如:使用者的大頭照放在 Facebook,而某個第三方軟體如 iT 邦幫忙,想取得使用者的大頭照,必須要經過使用者授權。注意:要或不要的決定權在於使用者。
系統管理者,或被授權的使用者,才有權利更改存取控制的策略。目的是管理並控制使用者存取資源的權限。
如:留言板系統,前台使用者只能留言,後台使用者可以刪除留言。再一次與授權比較如下:
首先要了解 OAuth2 所定義的角色:
而這四個角色之間的互動如下:
下圖源自 RFC 6749 1.2
@startuml
Client -> ResourceOwner: (1) Authorization Request
Client <- ResourceOwner: (2) Authorization Grant
Client -> AuthorizationServer: (3) Authorization Grant
Client <- AuthorizationServer: (4) Access Token
Client -> ResourceServer: (5) Access Token
Client <- ResourceServer: (6) Protected Resource
@enduml
以「iT 邦幫忙,想取得使用者在 Facebook 的大頭照」為例:
從上面這個流程可以發現,除了第二步不明確之外,其他流程都很清楚:要求授權,使用者同意即可拿到 access token,接著就可以拿到想要拿的資源。
OAuth2 是一個設計很靈活的框架,不但預定義了四種授權類型,同時也保留了彈性可以自定義類型,如 RFC 7521 - Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants 是利用 Assertion(如 SAML Assertion 或 JWT)來換取 access token 的框架。
預定義的授權類型如下:
其中 client credentials grant 類似之前 API 身分驗證所提到的信任服務機制,屬於服務與服務之間的串接,而不經由使用者。
@startuml
Client --> AuthorizationServer: Client Authentication
Client <-- AuthorizationServer: Access Token
@enduml
其他三種授權類型都會經由使用者,其中最簡單,同時也被定義為最後無路可走才能用的方法為 resource owner password credentials grant,簡單來說,它是使用者將帳號密碼直接提供給第三方應用程式,而第三方應用程式再拿來向授權伺服器要求 access token。
@startuml
ResourceOwner -> Client: Resource Owner Password Credentials
Client --> AuthorizationServer: Resource Owner Password Credentials
Client <-- AuthorizationServer: Access Token
@enduml
Resource owner password credentials grant 只能用在授權伺服器對第三方應用程式有足夠的信任(如,公司內部服務串接),不然像 Facebook 帳號密碼提供給第三方應用程式處理,其實是非常不安全的。
Implicit grant 可以用於如 SPA 或 App 等,沒有後端服務的場景。
@startuml
UserAgent -> AuthorizationServer: Authorization Request
UserAgent <- AuthorizationServer: Authorization Grant
UserAgent -> AuthorizationServer: Resource Owner Authenticates
UserAgent <- AuthorizationServer: Redirection URI with Access Token in Fragment
UserAgent -> ResourceServer: Request Resource
@enduml
從圖可以了解,access token 最終會存放在 UserAgent 裡,這其實不是很安全的方法,只要 UserAgent 有漏洞,token 就有可能外流。
一般最常見,也相較安全的方法還是使用 authorization code grant 較多。明天將會對此流程做比較詳細的說明。