iT邦幫忙

2022 iThome 鐵人賽

DAY 29
0

介紹

OAuth,本意是做授權(Authorization)管理
OAuth 2.0 是一個授權的流程

OAuth 2.0 Authorization FrameworkRFC 6749 定義的一套 授權規格,任何程式語言都可以依照此規格實作出自己的授權系統

• 主要用來控制 用戶端 能在 有限範圍內 存取 資源擁有者資源
- 用戶端 = Client = 第三方應用程式、Web API
- 資 源 = Resource = 資料、功能
- 資源擁有者 = 擁有 資源 的人或對象(組織、程式、背景排程)
- 有限範圍內 = 授權需將資源進行一定程度的分類,區分不同範圍

以下情境是林心如在蝦皮網站使用Facebook的快速登入

在以上的範例中
資源伺服器:facebook,
資源擁有者:林心如
Client:蝦皮網站

Client 可能是Web API 也有可能是瀏覽器
相對資源擁有者的Clinet端

授權架構

OAuth 2.0 有4種授權流程

傳統未實作授權的資源存取架構

傳統的簡易授權架構

傳統授權架構的問題

認識 OAuth 2.0 重要的角色定義

理解 OAuth 2.0 的授權流程

情境1:

User透過瀏覽器,連到一個伺服器,這網站會再去找facebbook進行授權認證拿到token,在這邊該伺服器相對於Facebook就是屬於Client

情境2:

access token 存在前端是不安全的

User透過瀏覽器直接跟Facebook要token,這時候相對於Facebook來說
瀏覽器就是Client,通常這種都是屬於SPA,透過JS直接跟授權伺服器要token

練習 使用PostMan走一次流程

https://notify-bot.line.me/zh_TW/

{
 "info": {
  "_postman_id": "519b120c-e545-45f7-8209-731a2c8495d3",
  "name": "LINE Notify",
  "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
 },
 "item": [
  {
   "name": "發送 LINE Notify 通知訊息",
   "request": {
    "method": "POST",
    "header": [],
    "body": {
     "mode": "urlencoded",
     "urlencoded": [
      {
       "key": "message",
       "value": "Hello World",
       "type": "text"
      }
     ]
    },
    "url": {
     "raw": "https://notify-api.line.me/api/notify",
     "protocol": "https",
     "host": [
      "notify-api",
      "line",
      "me"
     ],
     "path": [
      "api",
      "notify"
     ]
    }
   },
   "response": []
  },
  {
   "name": "取得目前 Access Token 狀態",
   "request": {
    "method": "GET",
    "header": [],
    "url": {
     "raw": "https://notify-api.line.me/api/status",
     "protocol": "https",
     "host": [
      "notify-api",
      "line",
      "me"
     ],
     "path": [
      "api",
      "status"
     ]
    },
    "description": "*   [LINE Notify API Document](https://notify-bot.line.me/doc/en/)\n*   [管理登錄服務(服務提供者用)](https://notify-bot.line.me/my/services/)\n*   [上手 LINE Notify 不求人:一行代碼都不用寫的推播通知方法](https://blog.miniasp.com/post/2020/02/17/Go-Through-LINE-Notify-Without-Any-Code)"
   },
   "response": []
  },
  {
   "name": "撤銷目前 Access Token",
   "request": {
    "method": "POST",
    "header": [],
    "body": {
     "mode": "urlencoded",
     "urlencoded": []
    },
    "url": {
     "raw": "https://notify-api.line.me/api/revoke",
     "protocol": "https",
     "host": [
      "notify-api",
      "line",
      "me"
     ],
     "path": [
      "api",
      "revoke"
     ]
    }
   },
   "response": []
  }
 ],
 "auth": {
  "type": "oauth2",
  "oauth2": [
   {
    "key": "useBrowser",
    "value": true,
    "type": "boolean"
   },
   {
    "key": "client_authentication",
    "value": "body",
    "type": "string"
   },
   {
    "key": "grant_type",
    "value": "authorization_code",
    "type": "string"
   },
   {
    "key": "tokenName",
    "value": "LINE Notify AccessToken",
    "type": "string"
   },
   {
    "key": "clientSecret",
    "value": "{{ClientSecret}}",
    "type": "string"
   },
   {
    "key": "clientId",
    "value": "{{ClientID}}",
    "type": "string"
   },
   {
    "key": "scope",
    "value": "notify",
    "type": "string"
   },
   {
    "key": "accessTokenUrl",
    "value": "https://notify-bot.line.me/oauth/token",
    "type": "string"
   },
   {
    "key": "authUrl",
    "value": "https://notify-bot.line.me/oauth/authorize",
    "type": "string"
   },
   {
    "key": "state",
    "value": "123123",
    "type": "string"
   },
   {
    "key": "redirect_uri",
    "value": "https://www.getpostman.com/oauth2/callback",
    "type": "string"
   },
   {
    "key": "addTokenTo",
    "value": "header",
    "type": "string"
   }
  ]
 },
 "event": [
  {
   "listen": "prerequest",
   "script": {
    "type": "text/javascript",
    "exec": [
     ""
    ]
   }
  },
  {
   "listen": "test",
   "script": {
    "type": "text/javascript",
    "exec": [
     ""
    ]
   }
  }
 ]
}

詳細分析每個步驟

第一步:會先收到Http302轉址

https://access.line.me/dialog/oauth/weblogin?response_type=code&client_id=1476232700&redirect_uri=https%3A%2F%2Fnotify-bot.line.me%2Flogin%2Fcallback&state=8i0I4XQgzWDyLvDWK2aPlo

分析網址內容:
https://access.line.me/dialog/oauth/weblogin?response_type=code
response_type = code 走的是授權碼流程
client_id => 代表 LineNotify 這個Client
redirect_uri =>等整個流程走完 會需要透過這個回到LineNotify的網站,這個網址需要先註冊好
state=>亂碼 避免中間人攻擊

第二步:會先收到Http302轉址 取得授權

練習用網站 https://webhook.site/

https://notify-bot.line.me/oauth/authorize?response_type=code&client_id=ejpZDjZDiDr8r9qdjUzsQ8&state=123123&scope=notify&redirect_uri=https%3A%2F%2Foauth.pstmn.io%2Fv1%2Fcallback

authorzie endpoint:https://notify-bot.line.me/oauth/authorize

偷偷把redirect_uri 改成以下
https://webhook.site/#!/05f7fee1-51d7-4399-b270-ab182dd66934

如以下
https://notify-bot.line.me/oauth/authorize?response_type=code&client_id=ejpZDjZDiDr8r9qdjUzsQ8&state=123123&scope=notify&redirect_uri=https://webhook.site/05f7fee1-51d7-4399-b270-ab182dd66934

第三步:會再收到Http302轉址 取得code
https://webhook.site/05f7fee1-51d7-4399-b270-ab182dd66934?code=UthUbg86Ey8aWYS6J4FaSS&state=123123
他會給一段code

第四步:可以透過code 去跟LINE取得access Token

Line Notify 流程圖

Access Token (存取權杖)

• 用來<證明存取權限的一組字串,可以讓 資源伺服器 (Resource Server)識別是否為信任的用戶端來源,並允許存取受限範圍的受保護資源

• Access Token 可以存放許多內容,但 OAuth 2.0 並未規範一定要放什麼:

  • 允許存取的範圍 (Scopes)
  • 明確的使用期限 (Expires)
  • 使用者識別資訊 (ID)

• 不應該存放敏感的使用者資訊,如帳號密碼、信用卡號等等。
• 字串可以為任意格式,只須讓 Resource Server 能夠識別即可

  • 大部分 OAuth 2.0 提供者都用 JWT 作為 Access Token 的格式,但非必要

OAuth 2.0 的 4 種授權流程

RFC 6749 定義了 4 種授權的流程

  • 授權碼 Authorization Code Grant
  • 隱含授權 Implicit Grant
  • 密碼認證 Resource Owner Password Credentials (ROPC) Grant
  • 用戶端認證 Client Credentials Grant
    • 服務提供商可依需求進行部分實作
    • 服務提供商也可以自行擴充新的授權流程
  • Extension Grants
  • 裝置授權 Device Authorization Grant (RFC 8628)

授權碼 (Authorization Code) 運作流程


https://datatracker.ietf.org/doc/html/rfc6749?#section-4.1

授權碼 (Authorization Code) 主要特性

適合 用戶端 (Client) 位於 受信任 的環境 (大多是 Web 應用程式)

  • 基本限制
    • 需要透過瀏覽器進行轉址 (User-Agent Redirection)
  • 備註說明
    • 授權伺服器可以驗證用戶端的身分 (透過 OpenID Connect 登入)
    • 授權伺服器需詢問資源擁有者是否要授權用戶端要求的權限
    • 授權伺服器可以視需要核發 Refresh Token
  • 應用範例

隱含授權 (Implicit) 運作流程

隱含授權 (Implicit) 主要特性

適合 用戶端 (Client) 位於 不受信任 的環境 (大多是 SPA 應用程式)

  • 基本限制
    • 需要透過瀏覽器進行轉址 (User-Agent Redirection)
    • 此流程禁止核發 Refresh Token
  • 備註說明
    • 授權伺服器可以驗證用戶端的身分 (透過 OpenID Connect 登入)
    • 授權伺服器需詢問資源擁有者是否要授權用戶端要求的權限
  • 應用範例

密碼認證 (ROPC) 運作流程

密碼認證 (ROPC) 主要特性

  • 適合 資源擁有者用戶端 (Client) 高度互信 的環境 (如作業系統)
  • 基本限制
    • 當你的用戶端可以使用其他流程授權時,授權伺服器應禁止使用 ROPC 流程
    • 用戶端取得 Access Token 之後,必須立即丟棄暫存的 ROPC (使用者密碼)
    • 授權伺服器在啟用 ROPC 流程後,應透過節流限制保護端點遭受暴力攻擊!
  • 備註說明
    • ROPC = Resource Owner Password Credentials = 資源擁有者密碼認證資訊
    • 授權伺服器可以視需要核發 Refresh Token
  • 應用範例

用戶端認證 (Client Cred.) 運作流程

用戶端認證 (Client Cred.) 主要特性

  • 適合沒有資源擁有者可以介入授權的情境 (如背景執行的服務排程執行的程式)
  • 基本限制
    • 當你的用戶端存取資源伺服器的過程可以得到控制時才能使用 (例如:限制來源 IP 存取)
    • 當你想讓用戶端直接代表某一個資源擁有者來進行操作資源伺服器時
  • 備註說明
    • 當企業有定期更換密碼的需求,使用此流程是最簡單的 (直接改密碼即可)
    • 當用戶端遭受到入侵,可直接在授權伺服器停用用戶端即可
  • 應用範例

裝置授權 (Device Code) 主要特性

  • 適用於沒有瀏覽器輸入裝置受限的環境下
    • 例如:智慧電視、數位相框、印表機、智慧家庭主機 (有螢幕的那種)
  • 基本限制
    • 傳輸過程要求一定要走 TLS 加密連線
  • 備註說明
    • 這是一個擴充 OAuth 2.0 的授權流程,被定義在 RFC 8628 規格中
    • 要注意 User Code 的暴力攻擊,User Code 不宜太短,但太長又不方便輸入
  • 應用範例

裝置授權 (Device Code) 運作流程

  • 用戶端(裝置) 先透過裝置授權端點取得一組驗證碼並顯示在裝置上
    • 授權伺服器回應一組 JSON 資料 (包含幾個重要的驗證碼與到期時間)
  • 資源擁有者透過其他裝置連接 verification_uri 並填入 user_code
    • 你可以顯示 QR Code 讓使用者用手機進行掃描,但顯示 QR Code 的同時也建議顯示完整的 URL 在裝置畫面上,且該網址不建議直接包含 user_code 資訊
  • 用戶端(裝置) 持續輪詢 (polling) 發出 Device Access Token 要求
    ( grant_type=urn:ietf:params:oauth:grant-type:device_code, device_code, client_id )
    • 尚未授權時會回應 HTTP 400 與以下 JSON 結果
      { "error": "authorization_pending" }
    • 資源擁有者完成授權流程後,用戶端(裝置)會取得 Access Token
    • OAuth 2.0 Device Code Flow

關於jwt、各個平台的串接實作之後會專門寫一篇文章跟大家講解

參考資料

《線上授課》精通 OAuth 2.0 授權框架

本篇已同步發表至個人部落格
https://moushih.com/2022ithome29/


上一篇
玩轉C#之【SignalR】
下一篇
玩轉C#之【CDN】
系列文
玩轉C# 進階學習之旅31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言