利用github构建静态博客数据库
引言
因为使用如hexo
的框架搭建博客,是静态的,但是难免会有一些使用动态数据的需求产生,面对这些需求时,选择机械地编写硬编码,再上传生成显然不是一个优雅的做法。
而目前大多框架的主题都带有评论系统,其中支持gitalk
的便使用了OAuth
以及github
中的issue
,通过OAuth
授权验证,issue
作为存储。那么我们可以考虑利用这种模式,将动态数据更新到特定repo
的某个issue
中,再通过github
提供的API
访问获取数据。除此之外,关于这个存储repo
,虽然不能私有,但是其中的issue
可以选择关闭,只有管理员可以浏览编辑。这就只剩下一个问题,数据泄露,如果有比较机密的数据,当然不适合用这种方法了。(不会真有人往博客里写秘密吧,谁把秘密写在博客里,能写在博客的那能叫秘密吗?)
认识gitalk
看明白gitalk的工作原理,就成功大半了。
我,前端菜鸡,看到前端代码就头疼,能瞎写绝不优化。差不多就行了。
github token
此章参考Gitalk 运作原理,Gitalk,Github文档。token
分为三类,gitalk
使用OAuth App
,属于github的三种
token`之一。
- GitHub Apps
- OAuth Apps
- Personal access tokens
OAuth Apps
实现了OAuth2.0
认证协议,主要针对第三方平台想要通过GitHub API
获取用户私密信息时,用户可不必向第三方平台提供GitHub
账号密码即可完成认证。通过OAuth Apps
授权的token
代表的是该授权用户,而不是App
,即App
本身不具有任何权限。在权限限制上也与GitHub App
不同,OAuth App
只能读。值得一提的是GitHub
使用的是Authorization code grant
模式,也是最推荐的模式。以gitalk
为例在该模式下的认证流程为
OAth2.0 协议
OAuth2 有4个角色:
- 资源拥有者 (user)
- 第三方客户端 (client)
- 资源服务器 (resource server)
- 认证服务器 (authentication server)
Authentication code grant 模式流程如下:
- user在第三方平台A登录,登录方式是使用另一个平台B的身份信息。
- A携带clientID跳转到B的授权页,请user授权。(这个clientID就是A在B登记的OAuth身份标识,这也表明使用OAuth协议前必须先在平台注册登记)
- user授权A可以从B获取身份信息,grant_code作为凭据。
- A的【后台】向B发起access_token申请,携带参数clientID+clientSecret+grant_code。
- B验证无误后返回代表该用户的access_token。
- A可以使用access_token通过B的API调取user信息了。
可以看出认证授权有两个阶段,这也是OAuth协议被认为安全的关键。第一阶段只能拿到一个临时许可令牌grant_code,可能十几分钟的过期。第二阶段拿access_token。
- 第一阶段
clientID可以保存在前端,比如web页面,跳转认证时直接从前端取,不需要请求后台。grant_code只作为一个用户许可,并不能确保是否是可信任平台发起的请求,所以要验证平台是否可信,通过clientSecret。 - 第二阶段
clientSecret只能保存在后台,而且获取access_token的请求只能由后台服务器发起和接收。这个过程跟前端无关,所以被认为是最安全的。
access_token一般会被保存起来,过期时间会久一些,可能几个月。
既然如此,是否可以说凡是使用OAuth2.0的认证就一定是最安全的呢?并不是,这要看是否使用的规范。gitalk就是一个不规范使用的例子,它把clientSecret也暴露在前端。因为我们没有后台。无后台server。缺点是暴露了clientSecret,不符合OAuth2.0规范。但是在GitHub上这样做是安全的,因为access_token只有读权限,不能对user的repo造成任何损害。
gitalk
源码
gitalk没有后台server,clientSecret也是保存在前端,它的代理服务器地址。
gitalk的代码,使用的代理
1 | proxy: 'https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/access_token', |
一个公开的免费代理,声称是不会保存任何转发信息。
-
1
2
3
4
5
6
7get accessToken () {
return this._accessToke || window.localStorage.getItem(GT_ACCESS_TOKEN)
}
set accessToken (token) {
window.localStorage.setItem(GT_ACCESS_TOKEN, token)
this._accessToken = token
}access_token获取之后被保存起来,不关闭浏览器是不需要重复授权的。
-
1
2
3
4
5
6createIssue () {
const { owner, repo, title, body, id, labels, url } = this.options
return axiosGithub.post(`/repos/${owner}/${repo}/issues`, {
title,
labels: labels.concat(id),
body: body || `${url} \n\n ${注意labels后面连接的id,这个id就是文章的唯一标识,一般设置为URL。
GitHub的label长度限制在63字符之内,超过就不能创建Issue。为此可以对URL进行md5哈希,md5后生成128-bit摘要,用16进制表示,长度恒等于32.
Issues获取也是根据labels,不同文章的id不同,获取的列表自然也就不同,把Issues作为评论展示出来,这样一个简单的评论系统就完成了。
读取issue
这个简单,通过github api就完事了,有一定的次数限制,不过可以添加token授权来解除上限,带上token后续也可以做一些其他的操作,上锁、删除等等。
官方文档:issue API
主要用到的就是获取具体内容,其中的评论等。
1 | get https://api.github.com/repos/USER_NAME/repo_NAME/issues/number |
写个XMLHttpRequest
请求。
写入issue
写入比较麻烦,因为只读的请求是可以匿名的,写入修改是需要授权的,需要编写授权跳转页面,api地址https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8000/home.html
授权之后构造符合post请求的信息发送就可以了,但是要带上token,其中如果使用access token,不能直接明文记录,会被删除,可以分段记录在不同的变量拼接,当然了,会有一定的泄露风险,不过无所谓,只要授权不是最高级别的也没多大问题。
使用octokit
但是以上直接通过github API造轮子的办法比较繁琐,文档也没有太多例子,构造、测试非常的麻烦。所以可以直接用轮子,文档:octokit/rest.js,github页面:octokit/rest.js官方描述如下GitHub REST API client for JavaScript
,直接查文档就行了。构造octokit对象,把参数填完就可以了。非常方便。
octokit使用注意事项
因为使用octokit需要引入模块,官方给出了两种方式。
浏览器
Load @octokit/rest
directly from cdn.skypack.dev
1 | <script type="module"> |
Node
Install with npm install @octokit/rest
1 | const { Octokit } = require("@octokit/rest"); |
如果使用浏览器的话,直接引用,在script标签里编写函数就可以了。
如果在js文件中使用第二种方式,大概率会报错:Uncaught ReferenceError:require is not defined
,因为浏览器环境没有RequireJS,需要另外引入,比较麻烦。可以通过加载定义Require的库,或者使用browerify
,webpack
等工具将js文件重新打包成带依赖的文件,但是会变大很多。建议还是使用第一种方式。
实例
读取issue
1 | var onload = function () { |
按需解析json即可,匿名读取有限制,每分钟60次,一般没问题,如果需要解除限制,就带上clientID和Secret区请求。
使用octokit
1 | <body> |
其他的octokit编写也差不多,看文档配参数就行,文档十分完善。
一些bug
构建js代码时,会在hexo
博客上遇到一些坑,一般是因为其他插件造成的,比如Aplayer的代码注入或是重复载入 Aplayer.js 资源脚本问题,会在js文件头部注入<link>
标签,导致报错, 查阅官方文档给出的方式是在配置文件中加入
1 | aplayer: |
但也很可能没有卵用!最好的方式就是,卸载APlayer,然后重装一个hexo-tag-aplayer(反正我也不在页面内插入音乐盒子,文章里用hexo-tag-aplayer就够了),然后再添加上述配置。
参考
gitalk
:https://github.com/gitalk/gitalk
利用 github pages
与 github api
搭建博客:https://github.com/eyasliu/blog/issues/2
gitalk
的运作原理:https://carl-zk.github.io/blog/2020/03/03/gitalk-%E8%BF%90%E4%BD%9C%E5%8E%9F%E7%90%86/
github Issue
作为博客微型数据库的应用:https://removeif.github.io/theme/github-Issue-%E4%BD%9C%E4%B8%BA%E5%8D%9A%E5%AE%A2%E5%BE%AE%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%BA%94%E7%94%A8.html
透过Github Action
生成数据:https://blog.uiharu.top/archives/generate-links-json-via-github-action.html
利用github api
获取issue
的想法:https://github.com/isaaxite/blog/issues/44
github
文档的issues操作:https://docs.github.com/en/rest/reference/issues
github API
的调用教程:https://segmentfault.com/a/1190000015144126
利用github issue
实现评论插件:https://segmentfault.com/a/1190000011100934
octokit
文档:https://octokit.github.io/rest.js/v18
使用hexo-tag-aplayer
以及配置书写:https://easyhexo.com/3-Plugins-use-and-config/3-1-hexo-tag-aplayer/#%E4%BB%8B%E7%BB%8D
解决Aplayer
注入问题:https://blog.csdn.net/qq_27439819/article/details/105011943
利用github构建静态博客数据库