以前在使用 Github issues 搭建博客平臺的時候,研究過一番如何取得 Github 受權並調用 API 的辦法。後來選擇了較簡單的帳號密碼和 Token 的方法。可是有讀者反饋這樣的操做依然稍顯麻煩,且在第三方的頁面輸入帳號密碼總感受不安全。後來通過研究,總算找到了 Github App 這種更爲優雅的辦法。javascript
要回答這個問題,能夠直接套用官方文檔的說法:html
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.java
簡單翻譯一下,就是 Github App 能夠經過 Github 提供的認證信息去調用 Github API。ios
細心的讀者會發現,Github 還提供了一個叫作「OAuth App」的東西,它的使用方式和 Github App 很是相似,最大的不一樣點是 OAuth App 所獲取的權限都是固定且只讀的,用戶只能讀取固定的數據而不能修改數據;而 Github App 幾乎能夠獲取Github提供的全部功能權限,且所獲取的權限能夠被設定爲「只讀」,「可讀可寫」和「禁止訪問」,對於權限的受權粒度會更細。git
獲取了對某些操做的權限以後,咱們就可使用這些權限去搭建一個獨立的 App,好比一個第三方的 Github 客戶端等等,這也是 Github App 的實用之處。github
前文提到,Github App 能夠免去用戶在第三方頁面輸入帳號密碼或者 Token 的操做而完成受權,那麼它是怎麼作到的呢?其實說白了,它也是一種 OAuth 登陸的方式,只不過把獲取 Token 的方式從「用戶輸入」變成「由 Github 提供」。json
下面介紹這種登陸方式的流程:axios
要完成上述的流程,首先必須先註冊一個 Github App。跨域
進入 Github主頁,點擊用戶頭像,找到 Setting/Developer settings/Github Apps,而後點擊「New Github App」,便可進入編輯界面:安全
依次填入名稱(此處爲 SOMEONE:BLOG )、描述、主頁 URL 之後,關鍵要在User authorization callback URL
填入獲取受權後的回調地址,而後在Permissions
裏面設置一些須要用到的 API 讀寫能力。若是你但願這個 APP 只能本身用,那麼使用默認的Only on this account
,不然就選擇Any account
,最後點擊Create Github App
便可。
操做成功後,就能夠看到這個 APP 的信息了:
其中的 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 獲取某些權限:
用戶肯定後,會帶着受權碼重定向到給定的回調地址:
這時候,第三方頁面(這裏是 localhost:8080)已經拿到了受權碼,接下來就須要憑藉這個受權碼以及 APP 的 Client ID 和 Client secret 去兌換 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}`
複製代碼
到目前爲止,基本已經 OK 了,但還有一個很大的問題,就是目前的 Token 所拿到的數據都是「只讀」的,並不能對某個 Github 倉庫進行任何提交或修改的操做——這是由於此 Github APP 還未被倉庫所安裝,這也是和 OAuth APP 最大的不一樣。
以個人博客平臺 jrainlau.github.io 爲例,若是但願用戶可以經過 API 對某條 issue 發起評論等操作,我須要在這個倉庫裏安裝個人 Github APP:
進入 Github APP 編輯頁 Setting/Developer settings/Github Apps/SOMEONE:BLOG,找到左側的 Install App,而後選擇你的帳戶去安裝:
你能夠選擇帳戶下的全部倉庫或者僅某個倉庫去使用這個 APP。點擊受權之後,Github APP 安裝完畢。此時經過受權的倉庫均可以被用戶經過 API 進行讀寫操做了。
在博客平臺裏,經過這個 APP 評論的用戶,其外觀上的體現也會標註來自 Github APP: