以前在使用 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.
简单翻译一下,就是 Github App 能够经过 Github 提供的认证信息去调用 Github API。java
细心的读者会发现,Github 还提供了一个叫作“OAuth App”的东西,它的使用方式和 Github App 很是相似,最大的不一样点是 OAuth App 所获取的权限都是固定且只读的,用户只能读取固定的数据而不能修改数据;而 Github App 几乎能够获取Github提供的全部功能权限,且所获取的权限能够被设定为“只读”,“可读可写”和“禁止访问”,对于权限的受权粒度会更细。ios
获取了对某些操做的权限以后,咱们就可使用这些权限去搭建一个独立的 App,好比一个第三方的 Github 客户端等等,这也是 Github App 的实用之处。git
前文提到,Github App 能够免去用户在第三方页面输入帐号密码或者 Token 的操做而完成受权,那么它是怎么作到的呢?其实说白了,它也是一种 OAuth 登陆的方式,只不过把获取 Token 的方式从“用户输入”变成“由 Github 提供”。github
下面介绍这种登陆方式的流程:json
要完成上述的流程,首先必须先注册一个 Github App。axios
进入 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: