前言

有幸在加入仙女座星系之后能够给大家开发这么一个好用的站外工具和插件,当然这也少不了很多人的帮助和支持。

最先要提到的肯定是 hexo-blog-encrypt 的作者 MikeCoder 和其他所有对这个加密插件项目的贡献者(贡献者列表:https://github.com/MikeCoder/hexo-blog-encrypt/graphs/contributors ,如果没有他们首先开发出这个插件,猫猫在这里也没有什么能做的,虽然在很多方面我学习了很多很多知识,借鉴了很多人很多事物的作品才到今天这一步,也才有了我们即将要介绍的 hexo-plugin-matatakiFanLocker,两个作为 Matataki 站外的交互插件和脚本。

在这里,再次感谢以下几个项目给我的灵感和源代码支持:

  1. Gitalk: https://github.com/gitalk/gitalk
  2. Disqus: https://disqus.com/
  3. hexo-blog-encrypt: https://github.com/MikeCoder/hexo-blog-encrypt
  4. Hexo: https://hexo.io/
  5. utterances: https://github.com/utterance/utterances

如果没有以上项目的支持,不会有今天的 hexo-plugin-matataki 和 FanLocker

使用

上面说的东西不是很多,但是也不是很简单就能完成的,虽然的确是复制了别人好多的代码,但是,我们学习到了怎么去完成和实现才是最重要的不是吗?所以不阅读也没事,我们直接来描述怎么使用这个东西吧!

事不宜迟,不如先看看效果是什么样子的?看看演示博客

我在我的博客中也展示了如何使用这个插件,试试看解锁这篇文章吧!

我搭建了一个很简单的模版博客,在这个里面你可以看到这个插件完成的具体工作,我也会相应的给出一个 Hexo 博客的配置方案给大家参照去完成魔改。

如果阅读本文不是很清楚的时候可以参考这个仓库的 Hexo 配置来搭建你的博客:基础模版

从哪里开始呢?

我们最首先要知道的是,在 Hexo 中使用 hexo-plugin-matataki 是需要你在 Matataki 有注册账号,并且绑定过邮箱的,这样才能登录开发者中心,而 hexo-plugin-matataki 和 FanLocker 都是需要开发者中心才能完成他们的工作的。

首先前往Matataki 开发者中心,登录之后就可以看到这样的列表:

在这里就可以管理你的 App(我们称之为 App 是因为你可以使用我们的开发者中心提供的帮助和 API 接口以及 SDK 来完成许多 Matataki 外部应用的开发,当然如果只是写文章的你,不用在乎这些),以及你的团队,还有查阅开发文档。

创建属于博客的 App

我们在这里点击新建就可以新建一个属于你的博客的 App:

选择一个好看的图片,因为到时候会用到这个图片,大家会在使用 Matataki 账号登录到你的博客的时候看到这个图标,也可以看到你在这里填写的一切信息。

要注意这里填写的内容哦,这里填写的时候一定要注意回调链接这一栏,我们的服务器是不允许回调链接配置的时候超出域名范畴的,简单的来说,就是这里写上的域名,以及之后 FanLocker 帮你临时添加回调链接的时候必须是同一个域名,为什么会这样去限制呢?因为我们认为,FanLocker 把你的 client Id 和 client Secret 暴露在网页外部的时候,很可能会被外部的黑客利用,并且跳转到他们的网站,这样的话会给你的读者带来很多不安全的麻烦,所以我们限制了这个内容,只允许同域名的跳转。

当然,如果你是在本地尝试预览你的博客,hexo server 这个命令默认的端口号 4000,你可以在这里填写:

localhost:4000

这样本地测试链接回调的时候就会返回你本地的 localhost 了呢,但是要注意哦,当你部署到正式的域名下之后,要记得把回调链接改成你的博客域名地址,无论你的博客是否放在子域名或者子路径下,比如:xxx.com/blog 这才是你的博客的话,填写 xxx.com 也是没有问题的哦。

点击立即创建就可以了哦,你会在 App 列表中看到你创建的 App。

其他的内容在用户登录的时候也会展示出来,你可以前往 Oauth2 这个页面去查看你的 App Oauth 登录地址,可以看到在登录界面下,你填写的所有内容都是可以被用户查阅的。

这就是授权登录的界面。

我们下一步要做什么呢?配置你的 Hexo。

配置 Oauth

在 Oauth2 页面下获取到的这个链接,要在 Hexo 的根目录或者主题目录下创建一个键值,键值名称叫 fanlocker,填写的内容就是你的 Oauth 地址,粘贴进去就好了。

fanlocker: https://developer.matataki.io/app/a0df0a921ffc94f3/oauth

如果还是不清楚的话可以看这个链接:_config.yml:112

主题页面下到这里就结束了。

安装 hexo-plugin-matataki

我们现在在博客中添加我们的 hexo-plugin-matataki:

yarn add hexo-plugin-matataki@latest

如果你没有安装 yarn 只有 npm 的话也没问题哦,国内速度会稍为慢一些:

npm install hexo-plugin-matataki@latest

好啦,现在就大功告成了,Hexo 现在运行的时候就会去读取根目录下的 package.json 去加载这个插件。

我们现在在文章的 md 文件中只需要在开头的位置填写下面的内容就好了,

matataki:
  token: 填写你的 token id,这个 id 在你的 Fan 票详情页面地址栏里尾部的数字就是
  password: 你的加密密码,随机字符串就好
  name: 你的加密密码名称,要记住这个,我们之后还要用到
  amount: 需要多少数量才可以解密呢?填写数字就好了
  mode: hold 这里是模式,填写 hold 就好,将来会有支付的选项,可以填写 pay,但是现在还不行,我们写 hold 就好了

这里也有一些额外的参数可以选择和使用,比如

matataki:
 abstract: 这篇文章使用了 Fan 票加密,持有特定 Fan 票来解锁文章
 message: 持有 Fan 票来解锁文章
 wrongPassMessage: 解锁失败了呢。如果你是博客作者遇到这个问题,看看保险箱的键值对是否设置正确呢
 wrongHashMessage: 好像文章加密的时候的时候遗漏了几页呢,不过这些剩下的内容还是可以看看啦

这些参数分别作用在:

  1. abstract:文章外部,文章列表的地方会读取到的内容
  2. message:这个是文章内部的提示
  3. wrongPassMessage:这是加密密码正确的提示,通常是因为配置 name 错误导致的
  4. wrongHashMessage:这是加密全文丢失了部分内容导致的,通常是因为原文渲染不正确

还有一个额外参数,比如你希望不同的页面使用不同的 Oauth 地址,也可以在这里声明:

matataki:
    oauth: 你的 Oauth 地址

那么我们最后的文章编辑器可以看到这样的结果:

只要把这个内容放在 — 开头和 — 结尾的地方就好了呢。

现在我们要去魔改我们的主题,让我们的主题能够进行解锁。

如果你的文章内容涉及到了一些比如:ToC(目录,大纲),或者阅读时间,字数统计的话,你需要在字数统计的地方使用的

page.content

更换为

page.origin

就好了,这个地方使用的 origin 就是你的原文内容,如果你需要更多可以变更的选项,大都依赖这个值。

如果还有其他问题,请前往:https://github.com/nekomeowww/hexo-plugin-matataki/issues 提交你的问题和相应的原因。

添加 FanLocker 脚本

我们以 landscape 这个默认的主题来进行演示,如何进行修改。

我们定位到这个文件:

themes/landscape/layout/post.ejs

通常点进去你只会发现一行代码的内容,这个文件在渲染的过程中完成了你的文章独立页面的渲染,我们要在你的每一个文章页面渲染下都添加这个小代码:

<script src="https://unpkg.com/fanlocker@latest/dist/fanlocker.js"></script>
<script>
  let fl = new FanLocker({
    clientId: '<%- config.matataki.clientId %>',
    clientSecret: '<%- config.matataki.clientSecret %>'
  })
</script>

这段代码要求浏览器去加载最新版本的 FanLocker 脚本,这是需要联网才能获取的,在这点上我表示很抱歉我们不能做成本地存储的,当然你也可以把源代码下载下来,放置到你的 js 目录中使用本地加载:FanLocker 静态文件

在上面这段代码中,我们还引入了两个参数:

config.matataki.clientId

config.matataki.clientSecret

这两个参数我们可以到根目录配置文件的位置填上:_config.yml:113

matataki:
  clientId: 你在开发者中心获取的 Client ID
  clientSecret: 你在开发者中心获取的 ClientSecret

这两个参数我们要前往 App 的基本信息页面去获取:

点击复制就可以了,然后对应着粘贴到你的根目录配置文件内。

这一步到这里就结束了,但是还有最后一步,我们需要一个安全的地方来存储我们的密码。

设置密码键值对

再次前往开发者中心,我们去保险箱这个页面创建我们的密码和内容,点击右上角的「创建键值对」就可以创建了。

我们把我们之前在文件中填写的 name 参数和密码参数填写进来,名字和密码都不能错哦,不能有多余的字符,要不然之后就获取不到了。

点击立即创建就可以创建一个键值对。

在这里猫猫需要声明一下呢,如果你在文章页面不进行声明 name 的话,会默认使用你的文件名,也就是 Markdown 的文件名作为 name 参数进行获取,我们如果想要方便的管理密码和密码的对应名字,应该是设定一个固定的密码,这样可以重复使用的,当然,如果你在保险箱中心不创建任何东西,你的文章在加密的时候也不会和服务器进行任何连接和数据传输,所以就算你不想去指定一个 name,你也需要自己手动来完成这个创建的过程,因为这才是安全的办法。

创建之后就会返回保险箱主页,你可以看到你创建的键值对的名称,但是获取不到信息,在这里我们学习了 GitHub Secrets 的设计,我们不会在这里获取任何密钥信息,服务器只会返回你有的键值名称,如果你需要变更你的密码,点击更新就可以了。

到这里就一切就绪了。

要注意的内容

这里猫猫在开发的过程中遇到了一点小问题,Hexo 会使用本地 db.json 文件进行存储和临时数据的管理,如果你发现你的页面没有更新,那么你应该删除本地的 db.json 文件,如果之前有运行过 hexo g 这个命令,那你也应该优先运行 hexo clean 来清除之前的生成。

如果本地没有 db.json 文件,也没有 public 文件夹,那么我们就可以运行这个命令来看到我们的内容了:

hexo s --debug

如果你在加密的参数中更新了什么信息的话,建议再次删除 db.json 再去运行上面的命令。

发布

如果你准备好了发布你的博客,运行

hexo d

就好了

开发

怎么做呢?

其实在开发初期岛给我这个方向之后,我一开始思考的是怎么去做一个使用地址栏作为 query 的动态验证机制,因为在开始这两个项目之前我在开发的主要方向是 Matataki 的开发者中心:DeveloperPortal-FE/BE, 做的很多事情也是完成一个 Matataki 的第三方登录的机制,也就是众所周知的 Oauth2 授权,整个开发过程可以说是从基础模块去构建,去一步一步实现一整套完整的系统,到现在我们的 FanLocker 也就是完全基于开发者中心和 Matataki API 完成的所有工作。那么我是怎么解决这个问题的呢?

评论模块的启发

Hexo 用户可能很熟悉怎么去折腾评论模块,而我之前有接触过的两个评论模块都是使用了第三方登录,或者说使用了 Oauth(Gitalk)或者跳转登录(Disqus)的方式去完成,那么我想,如果要让开发者中心的 API 返回一个夹带着授权 token 的链接并且跳转到指定的地点,就需要一个 Window 相关的方法来动态检测和完成。我一步一步去 debug 和 trace back 了 disqus,gitalk,utterance 的登录方式,最后得出的结论是这样的:

  1. Disqus 的实现可能会慢一些,但是效果最好
  2. Gitalk 就是使用了 window 相关的 API 接口完成的(达成了我想要的结果)
  3. utterance 是后来认识的,debug 起来很简单,也是依赖 GitHub API Oauth 的结果

那么综上所述,我选择了去阅读 Gitalk 的源码,去一步一步了解过程的发生和结束,认证的开始和许可

Gitalk 怎么完成的?

const queryParse = (search = window.location.search) => {
    if (!search) return {}
    const queryString = search[0] === '?' ? search.substring(1) : search
    const query = {}
    queryString
        .split('&')
        .forEach(queryStr => {
            const [key, value] = queryStr.split('=')
            if (key) query[decodeURIComponent(key)] = decodeURIComponent(value)
        })
    return query
}

在这里我把源码贴出来,也就是 window.location.search 这个关键的变量在起作用,当你的地址栏中有,存在 ? 这个 query string 的时候,就会把这个部分和后面的所有字符串当作是一个 search 变量,我们使用这个封装好的方法就可以得到一个地址栏 parser 的函数。

我们怎么用?

当我们开发者中心返回了 &token=xxx 之后,我们在地址栏的尾部增加一个句段

?callback=true

当然我们还要发给 Oauth 服务器一个 redirect_uri 的请求,这样才能正常的返回我们的指定的文章页面,而不是死板的博客首页,基于这样的需求,我又去开发者中心后端添加了这个接口,能够动态变更和控制 redirect_uri。

于是我们先完成下面的请求:

axios.post(`https://developer.matataki.io/api/app/oauth`, { clientId: clientId, clientSecret: clientSecret, redirect_uri: `${window.location.origin}${window.location.pathname}?callback=true` })

这里的 window.location.origin 和 window.location.pathname 就是我们的博客页面和博客附属地址,以及我们需要的字段,这样服务器就会知道,在下一次即将完成的 Oauth 授权中,需要跳转到这个指定的位置。

当我们点击按钮,绑定的 click 事件就会触发这个解密的函数,去获取指定的密码来解锁文章。

每次进入文章独立的页面的时候就会加载这个脚本并且检查是否有可以获取的信息,当用户点击登录并且授权之后,返回 token 就可以被获取和加载了。这一部分的内容可以查阅开发者中心的用户信息获取的文档。

开发成两个分离的模块

为什么是两个独立的项目呢,虽然加密解密的过程是需要同步和一致的,但是我们使用了外部第三方 API(也就是开发者中心提供的保险箱 API)来完成这个解密的过程,也是因为我借鉴的主要项目是 Gitalk,我认为两者运行的代码应该是可分离可拆解的,所以变成了两个项目,

我们使用 hexo-plugin-matataki 在本地进行加密和生成,我们到了线上之后,使用 FanLocker 脚本进行动态的信息获取和解密文本。

hexo-plugin-matataki 在本地按照用户的策略来加密和生成文章的加密后内容和信息,以及所有的信息存储方式按照模版注入进去,然后我们在本地添加一个动态加载 FanLocker 的脚本作为每个文章页面的详情页面的解锁方案。

FanLocker 在运行的时候还会获取用户的钱包信息和用户 id 等等的基础内容,在获取之后我们进行比对,获取我们需要的 Fan 票 Id 来进行第一步校验,查看用户是否拥有这个指定的 Fan 票和指定数量的 Fan 票,如果有的话,我们进行第二步内容,我们使用提供的 client Id 和 client secret 来获取用户指定的密码,获取保险箱内容,最后使用获取的保险箱内容进行解密。

到这里就完成了我们所有的内容整合,集成和运行。

最后

谢谢你阅读到这里,也感谢你选择和使用 Matataki 和开发者中心,以及我们提供的 hexo-plugin-matataki 提供的站外解锁的方案。

再一次我们不得不感谢以下几个项目给我的灵感和源代码支持:

  1. Gitalk: https://github.com/gitalk/gitalk
  2. Disqus: https://disqus.com/
  3. hexo-blog-encrypt: https://github.com/MikeCoder/hexo-blog-encrypt
  4. Hexo: https://hexo.io/
  5. utterances: https://github.com/utterance/utterances

谢谢他们给我的源代码和灵感的实现。

链接

预览 hexo-plugin-matataki 的样式:https://neko.ayaka.moe/hexo-plugin-matataki-showcase/
搭建博客的参考配置:https://github.com/nekomeowww/hexo-plugin-matataki-example
hexo-plugin-matataki 源码:https://github.com/nekomeowww/hexo-plugin-matataki
FanLocker 源码:https://github.com/nekomeowww/fanlocker
Matataki 开发者中心:https://developer.matataki.io