详解 Github App 的玩法

image

以前在使用 Github issues 搭建博客平台的时候,研究过一番如何取得 Github 受权并调用 API 的办法。后来选择了较简单的帐号密码和 Token 的方法。可是有读者反馈这样的操做依然稍显麻烦,且在第三方的页面输入帐号密码总感受不安全。后来通过研究,总算找到了 Github App 这种更为优雅的办法。javascript

什么是 Github App

要回答这个问题,能够直接套用官方文档的说法: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.

简单翻译一下,就是 Github App 能够经过 Github 提供的认证信息去调用 Github API。java

细心的读者会发现,Github 还提供了一个叫作“OAuth App”的东西,它的使用方式和 Github App 很是相似,最大的不一样点是 OAuth App 所获取的权限都是固定只读的,用户只能读取固定的数据而不能修改数据;而 Github App 几乎能够获取Github提供的全部功能权限,且所获取的权限能够被设定为“只读”,“可读可写”和“禁止访问”,对于权限的受权粒度会更细。ios

image

获取了对某些操做的权限以后,咱们就可使用这些权限去搭建一个独立的 App,好比一个第三方的 Github 客户端等等,这也是 Github App 的实用之处。git

第三方登陆的原理

前文提到,Github App 能够免去用户在第三方页面输入帐号密码或者 Token 的操做而完成受权,那么它是怎么作到的呢?其实说白了,它也是一种 OAuth 登陆的方式,只不过把获取 Token 的方式从“用户输入”变成“由 Github 提供”。github

下面介绍这种登陆方式的流程:json

  1. A 网站跳转到 Github 的受权页面。
  2. Github 受权页面询问用户:“是否容许A网站获取下列权限”,用户点击“容许”,取得受权码。
  3. Github 受权页面重定向回 A 网站,同时在URL 上带上受权码。
  4. A 网站经过 URL 上的受权码往 Github 取回 Token。
  5. A 网站使用这个 Token 去调用 Github API。

要完成上述的流程,首先必须先注册一个 Github App。axios

注册 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

参考资料

相关文章
相关标签/搜索