詳解 Github App 的玩法

Jrain發表於2019-05-30

image

之前在使用 Github issues 搭建部落格平臺的時候,研究過一番如何取得 Github 授權並呼叫 API 的辦法。後來選擇了較簡單的賬號密碼和 Token 的方法。但是有讀者反饋這樣的操作依然稍顯麻煩,且在第三方的頁面輸入賬號密碼總感覺不安全。後來經過研究,總算找到了 Github App 這種更為優雅的辦法。

什麼是 Github App

要回答這個問題,可以直接套用官方文件的說法:

GitHub Apps are first-class actors within GitHub. A GitHub App acts on its own behalf, taking actions via the API directly using its own identity, which means you don't need to maintain a bot or service account as a separate user.

簡單翻譯一下,就是 Github App 可以通過 Github 提供的認證資訊去呼叫 Github API。

細心的讀者會發現,Github 還提供了一個叫做“OAuth App”的東西,它的使用方式和 Github App 非常類似,最大的不同點是 OAuth App 所獲取的許可權都是固定只讀的,使用者只能讀取固定的資料而不能修改資料;而 Github App 幾乎可以獲取Github提供的所有功能許可權,且所獲取的許可權可以被設定為“只讀”,“可讀可寫”和“禁止訪問”,對於許可權的授權粒度會更細。

image

獲取了對某些操作的許可權之後,我們就可以使用這些許可權去搭建一個獨立的 App,比如一個第三方的 Github 客戶端等等,這也是 Github App 的實用之處。

第三方登入的原理

前文提到,Github App 可以免去使用者在第三方頁面輸入賬號密碼或者 Token 的操作而完成授權,那麼它是怎麼做到的呢?其實說白了,它也是一種 OAuth 登入的方式,只不過把獲取 Token 的方式從“使用者輸入”變成“由 Github 提供”。

下面介紹這種登入方式的流程:

  1. A 網站跳轉到 Github 的授權頁面。
  2. Github 授權頁面詢問使用者:“是否允許A網站獲取下列許可權”,使用者點選“允許”,取得授權碼。
  3. Github 授權頁面重定向回 A 網站,同時在URL 上帶上授權碼。
  4. A 網站通過 URL 上的授權碼往 Github 取回 Token。
  5. A 網站使用這個 Token 去呼叫 Github API。

要完成上述的流程,首先必須先註冊一個 Github App。

註冊 Github App

進入 Github主頁,點選使用者頭像,找到 Setting/Developer settings/Github Apps,然後點選“New Github App”,即可進入編輯介面:

image

依次填入名稱(此處為 SOMEONE:BLOG )、描述、主頁 URL 以後,關鍵要在User authorization callback URL填入獲取授權後的回撥地址,然後在Permissions裡面設定一些需要用到的 API 讀寫能力。如果你希望這個 APP 只能自己用,那麼使用預設的Only on this account,否則就選擇Any account,最後點選Create Github App即可。

操作成功後,就可以看到這個 APP 的資訊了:

image

其中的 Client ID 和 Client secret 就是這個應用的身份識別碼,需要記下來。

Github App 註冊完畢,接下來就需要第三方網站使用這個 APP 的 Client ID 去找 Github 要授權碼了。

獲取授權碼

第三方網站要獲取授權碼,只需要讓頁面跳轉到 Github 授權頁即可,其中需要在 URL 中攜帶兩個引數,分別是 Client ID 和 Redirect URL。

const CLIENT_ID = 'app 的 client id'
const REDIRECT_URL = 'app 的 redirect_url'

location.href = `https://github.com/login/oauth/authorize?` + 
`client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URL}`
複製程式碼

跳轉後,Github 會詢問使用者是否允許這個 APP 獲取某些許可權:

image

使用者確定後,會帶著授權碼重定向到給定的回撥地址:

image

這時候,第三方頁面(這裡是 localhost:8080)已經拿到了授權碼,接下來就需要憑藉這個授權碼以及 APP 的 Client ID 和 Client secret 去兌換 Token 了。

兌換 Token

兌換 Token 的程式碼如下:

router.post('/oauth', async function (ctx, next) {
  const { clientID = CLIENT_ID, clientSecret = CLIENT_SECRET, code } = ctx.request.body
  const { status, data } = await axios({
    method: 'post',
    url: 'http://github.com/login/oauth/access_token?' +
    `client_id=${clientID}&` +
    `client_secret=${clientSecret}&` +
    `code=${code}`,
    headers: {
      accept: 'application/json'
    }
  }).catch(e => e.response)
  ctx.body = { status, data }
})
複製程式碼

由於跨域限制,所以這部分的程式碼必須通過服務端實現,換句話說,A 網站拿到授權碼以後,需要發往這個服務端,由服務端獲取 Token 後再重新返回給 A 網站。

A 網站拿到服務端返回的 Token 以後,就可以通過設定 Header 的方式在呼叫 Github API 的時候使用了:

'Authorization': `Bearer ${Token}`
複製程式碼

image

image

到目前為止,基本已經 OK 了,但還有一個很大的問題,就是目前的 Token 所拿到的資料都是“只讀”的,並不能對某個 Github 倉庫進行任何提交或修改的操作——這是因為此 Github APP 還未被倉庫所安裝,這也是和 OAuth APP 最大的不同。

安裝 Github APP

以我的部落格平臺 jrainlau.github.io 為例,如果希望使用者能夠通過 API 對某條 issue 發起評論等操做,我需要在這個倉庫裡安裝我的 Github APP:

進入 Github APP 編輯頁 Setting/Developer settings/Github Apps/SOMEONE:BLOG,找到左側的 Install App,然後選擇你的賬戶去安裝:

image

你可以選擇賬戶下的所有倉庫或者僅某個倉庫去使用這個 APP。點選授權以後,Github APP 安裝完畢。此時通過授權的倉庫都可以被使用者通過 API 進行讀寫操作了。

在部落格平臺裡,通過這個 APP 評論的使用者,其外觀上的體現也會標註來自 Github APP:

image

參考資料

相關文章