likes
comments
collection
share

详解 Github App 的玩法

作者站长头像
站长
· 阅读数 9

详解 Github App 的玩法

之前在使用 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提供的所有功能权限,且所获取的权限可以被设定为“只读”,“可读可写”和“禁止访问”,对于权限的授权粒度会更细。

详解 Github App 的玩法

获取了对某些操作的权限之后,我们就可以使用这些权限去搭建一个独立的 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”,即可进入编辑界面:

详解 Github App 的玩法

依次填入名称(此处为 SOMEONE:BLOG )、描述、主页 URL 以后,关键要在User authorization callback URL填入获取授权后的回调地址,然后在Permissions里面设置一些需要用到的 API 读写能力。如果你希望这个 APP 只能自己用,那么使用默认的Only on this account,否则就选择Any account,最后点击Create Github App即可。

操作成功后,就可以看到这个 APP 的信息了:

详解 Github 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 获取某些权限:

详解 Github App 的玩法

用户确定后,会带着授权码重定向到给定的回调地址:

详解 Github App 的玩法

这时候,第三方页面(这里是 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}`

详解 Github App 的玩法

详解 Github App 的玩法

到目前为止,基本已经 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,然后选择你的账户去安装:

详解 Github App 的玩法

你可以选择账户下的所有仓库或者仅某个仓库去使用这个 APP。点击授权以后,Github APP 安装完毕。此时通过授权的仓库都可以被用户通过 API 进行读写操作了。

在博客平台里,通过这个 APP 评论的用户,其外观上的体现也会标注来自 Github APP:

详解 Github App 的玩法

参考资料