Hexo NexT使用Gitalk评论区
本文简要介绍一下如何在博客使用Gitalk评论区,并移除其他评论区的过程。对于具体的细节则不会做过多解释,主要展示步骤。
本文运行环境:
1 | node: v18.16.1 |
引言
最近测试了NexT集成的一些评论区,它们各有各的缺点。早期的时候,Valine评论区集成在NexT中,后来被移除,具体在这条GitHub Issue中有说明。虽然可以设法保留,但是终归不是好办法。Disqus是个相对好用的评论区,但是免费版的广告太过恼人,不仅不能设置广告类型(虽然官网声称支持但实测无效),而且也没有关闭的选项。虽然可以被用户使用的浏览器广告屏蔽插件屏蔽掉,但是不能对此有依赖。广告对博客的整体观感造成了影响。之后切换了来必力 (LiveRe),但是此服务有点小众,不太接地气,用户不太可能为此专门注册一个账号来评论,不仅用户不便,也不利于博客的发展。
思前想后,感觉还是得回归Gitalk。它是一个基于 GitHub Issue 和 Preact 开发的评论插件,除了 GitHub 账号之外不需要其他依赖(看我博客的人应该都有GitHub账号吧?),也不需要注册其他账号。NexT主题已经支持了Gitalk。下面简述一下配置步骤。
注册 GitHub Application
使用Gitalk的前提是:
- 一个公共的GitHub存储库用于存储评论
- 创建一个 GitHub Application
其中第一步当前已经满足,你的博客本身就是你的GitHub公共存储库,直接使用即可。当然你也可以新建一个存储库专门用于评论区。下面完成第二步。
点击这里申请 GitHub Application,网页标题为 “Register a new OAuth application”。需要填写如下内容:
- Application name:应用名称,我在这里填写了
hexo-blog-comments
。 - Homepage URL:你的应用主页,这里填写博客主页地址。记住要携带
https
协议,如果你的博客是个人域名,请使用域名而不是*.github.io
。 - Application description:你的应用描述,任何语言皆可。用你自己喜欢的文字描述。
- Authorization callback URL:这里要填写当前使用插件页面的域名,与Homepage URL相同即可。
点击“Register application”,在新页面可以看到Client ID,先记下。随后在“Client secrets”右侧点击“Generate a new client secret”,并记下生成的client secret。它只会显示一次,如果没有记下或者丢失了,就只好重建新的再删除旧的了。
以上准备工作完毕。如果你需要一个存储库专门用于评论区,直接在GitHub新建repository即可,这里就不赘述了。
配置 Gitalk
在_config.next.yml
中进行配置:
1 | # Gitalk |
如果你之前有其他的评论区,记得取消掉。具体方法就是查看附近的评论区设置,如果有enable: true
要改为false
,如果仅有一行配置(例如livere_uid
)记得注释掉。如果你有多评论区配置也要做相应修改(例如active: gitalk
),这里不再赘述。
评论区批量初始化
现在部署之后应该可以看到Gitalk评论区,但是处于未初始化的状态,而且每一篇文章都是这样的。显示的文字如下:
1 | 未找到相关的 Issues 进行评论 |
如果是全新的博客或许可以手动初始化,但是对于老博客来讲,这个成本有点高,因此需要批量初始化。本部分参考了这篇文章与这篇文章,并做了一些修改与优化。
申请 Personal Access Token
因为GitHub API对接口请求有限制,OAuth方式限制太低,不足以用于初始化评论区,因此需要Personal Access Token的方式来完成。在这里申请一个新的Token,网页标题为“New personal access token (classic)”。填写如下信息:
- Note:Token的使用目的,例如
hexo-blog-comments-init
。 - Expiration:选择“No expiration”,也就是无过期时间。
- Select scopes:选择Token的权限。这里需要以下权限:
repo:status
repo_deployment
public_repo
点击“Generate token”,获取新的Token。这里Token只会出现一次,请务必记下,否则又要重新创建了。
安装相关依赖
在项目根目录下运行命令:
1 | npm i request xml-parser blueimp-md5 moment hexo-generator-sitemap -S |
配置 hexo-generator-sitemap
如果没有安装hexo-generator-sitemap
,可以参考 Hexo NexT更多功能设置 进行配置。随后在_config.yml
添加或修改:
1 | sitemap: |
在项目根目录新建文件sitemap-template.xml
:
1 |
|
配置完成后使用hexo clean; hexo g
可以看到生成了public/sitemap.xml
。
添加自动初始化脚本
新建文件source/_scripts/gitalk-auto-init.js
,并写入如下内容(注意config
中的配置信息要符合你的博客):
1 | const fs = require('fs'); |
随后在package.json
新增:
1 | "scripts": { |
本地运行测试
执行hexo clean; npm run build; hexo s
进行本地部署。这里使用npm run build
的原因是上面在package.json
中进行了定义,使它兼具了hexo g
与Gitalk批量脚本的功能。也可以不使用npm run build
而单独执行这两条命令。
日志中应该出现如下内容:
1 | Gitalk 初始化开始... [ xxx | xxx ] |
这说明Issue评论区正在建立中。你可以去实际的评论区GitHub仓库里查看Issues是否存在来验证是否成功。
不为某些文章生成评论区
在本地测试中发现,无论文章是否具有comments: false
,都生成了对应的评论区Issue(虽然评论区依旧是关闭的,但是Issue存在)。如果不想看到此类行为,则需要做一些修改。
首先修改sitemap-template.xml
,加入如下内容:
1 | <?xml version="1.0" encoding="UTF-8"?> |
这是为了在public/sitemap.xml
生成时检测评论区是否开启,如果不开启,则直接不生成对应内容。
随后重新部署验证。可能需要清理一下已经存在的Issues。
远程部署
最后,修改工作流的如下内容(首先需要配置博客的自动部署,详情可以参考 Hexo静态博客指南:本站是如何诞生的(2021年版)):
1 | # Deploy |
随后提交代码出发自动部署即可。
Secondary rate limits 受限问题
虽然Personal Access Token有每日5000次的限制,足够使用,但仍然可能出发GitHub的Secondary rate limits:
1 | body: '{\n' + |
这会让远程部署报错。你可以尝试更改请求间隔来规避这个问题。示例更改代码如下:
1 | // 上面省略 |
之后进行重新部署测试。这可能会拉长部署时间,但只要生成了本地缓存文件就可以加速。
关于权限与安全问题的讨论
对Gitalk这类基于GitHub Issues的评论系统,权限与安全是绕不开的话题。该系统面临的主要问题如下:
- 对作者:
client_id
与client_secret
直接暴露在前端,可能会有安全隐患; - 对评论者:首次使用时需要授权GitHub账户,而该授权竟然要求所有公开仓库的读写权限,权限过于夸张,如果有恶意网站,甚至可以删光所有公共仓库。
关于第一点,这里有详细讨论。也有Issue针对这个问题做了说明,简要概括如下:
- 虽然 Gitalk 使用了第三方代理服务器来获取
access_token
属于违反 OAuth2.0 规范,但是作为一个评论系统来说安全性可以不必担心,因为GitHub已经对access_token
做了只读限制; - 获取或修改 GitHub 用户数据,需要
token
,为了拿到token
,除了需要 OAuth App 的client_id
和client_secret
外,还需要一个 Authorization Code; - 这个
code
是 GitHub 登录授权完成时,在跳转回redirect_uri
的查询参数拿到的,redirect_uri
必须是在 OAuth App 配置的 callback URL 域名下; - 这样即使别人用了你的
client_id
和client_secret
,跳转之后也拿不到 code,所以,有client_id
和client_secret
也做不了什么。
虽然如此,而且作为静态博客引擎,这样做是没有办法的办法,但是暴露client_id
与client_secret
终究是不太推荐的做法。
对于第二点,讨论更为广泛,Issue与帖子都有涉及。为什么需要这么高的权限,简而言之就是GitHub OAuth权限设计目前只能做到这样的粒度。Gitalk源码中,开发者没有保存 access_token
,只是将它保存到了 localStorage 中。但是可能会存在恶意的攻击者来扩展这一点。这对于评论者而言是一种伤害,如此之大的权限可能会降低评论者评论的意愿,毕竟网站有无恶意是很难判断的。目前的解决方案有两种:
- 点击评论区的统计数字,可以跳转到相应的GitHub Issue页面,在页面评论可以绕过验证;
- 采用更安全的评论系统,例如utterances这类App,它的权限仅限于某个仓库,可以一定程度上降低破坏性。
那么本博客该如何做?本着精益求精的原则,估计是又要迁移到 utterances 上了…… 刚刚迁移评论系统还没多久,就发现了这个问题。生命在于折腾,utterances 迁移会后续写文章处理。