搭建自己的GITMENT代理服务器

背景

我用hexo创建了个博客,使用的主题是NEXT,并且在主题内配置了gitment评论功能。
然而最近评论功能失效,登录后提示[object ProgressEvent]就探索了下解决办法。

原因

一句话概括:实现gitment功能的代理服务,SSL证书失效了。下面是过程分析。

next主题的gitment代码里,可以看到根据主题内gitment的mint配置,主题会引用不同的js文件,代码如下:

1
2
3
4
5
6
7
8
9
{% if theme.gitment.mint %}
{% set CommentsClass = "Gitmint" %}
<link rel="stylesheet" href="https://aimingoo.github.io/gitmint/style/default.css">
<script src="https://aimingoo.github.io/gitmint/dist/gitmint.browser.js"></script>
{% else %}
{% set CommentsClass = "Gitment" %}
<link rel="stylesheet" href="https://imsun.github.io/gitment/style/default.css">
<script src="https://imsun.github.io/gitment/dist/gitment.browser.js"></script>
{% endif %}

分别查看两个js文件内的gitment授权实现:

gitmint.browser.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
if (query.code) {
var _oauth = this.oauth,
client_id = _oauth.client_id,
client_secret = _oauth.client_secret,
proxy_gateway = _oauth.proxy_gateway;

var code = query.code;
delete query.code;
var search = _utils.Query.stringify(query);
var replacedUrl = '' + window.location.origin + window.location.pathname + search + window.location.hash;
history.replaceState({}, '', replacedUrl);

Object.assign(this, {
id: replacedUrl,
link: replacedUrl
}, options);

this.state.user.isLoggingIn = true;
var logging = !proxy_gateway ? _utils.http.post('https://gh-oauth.imsun.net', { code: code, client_id: client_id, client_secret: client_secret }, '') : _utils.http.post('/login/oauth/access_token', 'code=' + code + '&client_id=' + client_id, proxy_gateway);
logging.then(function (data) {
_this.accessToken = data.access_token;
_this.update();
}).catch(function (e) {
_this.state.user.isLoggingIn = false;
alert(e);
});
} else {
this.update();
}

gitment.browser.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if (query.code) {
var _oauth = this.oauth,
client_id = _oauth.client_id,
client_secret = _oauth.client_secret;

var code = query.code;
delete query.code;
var search = _utils.Query.stringify(query);
var replacedUrl = '' + window.location.origin + window.location.pathname + search + window.location.hash;
history.replaceState({}, '', replacedUrl);

Object.assign(this, {
id: replacedUrl,
link: replacedUrl
}, options);

this.state.user.isLoggingIn = true;
_utils.http.post('https://gh-oauth.imsun.net', {
code: code,
client_id: client_id,
client_secret: client_secret
}, '').then(function (data) {
_this.accessToken = data.access_token;
_this.update();
}).catch(function (e) {
_this.state.user.isLoggingIn = false;
alert(e);
});
} else {
this.update();
}

可以看到gitmint.browser.js多了代理的功能,如果没有配置代理地址proxy_gateway,二者均调用https://gh-oauth.imsun.net
如果配置了那么gitmint.broswer.js会调用代理地址(gitment内ajaxFactory函数会使用代理地址)。

对于gitment模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function renderGitment(){
var gitment = new {{CommentsClass}}({
id: window.location.pathname,
owner: '{{ theme.gitment.github_user }}',
repo: '{{ theme.gitment.github_repo }}',
{% if theme.gitment.mint %}
lang: "{{ theme.gitment.language }}" || navigator.language || navigator.systemLanguage || navigator.userLanguage,
{% endif %}
oauth: {
{% if theme.gitment.mint and theme.gitment.redirect_protocol %}
redirect_protocol: '{{ theme.gitment.redirect_protocol }}',
{% endif %}
{% if theme.gitment.mint and theme.gitment.proxy_gateway %}
proxy_gateway: '{{ theme.gitment.proxy_gateway }}',
{% else %}
client_secret: '{{ theme.gitment.client_secret }}',
{% endif %}
client_id: '{{ theme.gitment.client_id }}'
}});
gitment.render('gitment-container');
}

可以看到,如果关闭了mint或者不配置proxy_gateway时,项目会用client_secret渲染gitment插件,调用https://gh-oauth.imsun.net,带有client_idclient_secret参数;
如果开启了mint并且配置了proxy_gateway,渲染gitment插件时不会传入client_secret,所以此时需要通过其他方式让代理服务调用github oauth接口时带有client_secret

默认情况下,主题都是开启了mint(mint支持更丰富的gitment功能),并且将proxy_gateway置为空。在地址https://gh-oauth.imsun.net SSL 证书失效时,浏览器报错。

原理分析

github oauth 获取access_token的接口不支持CORS,那就需要一个支持CORS的服务进行代理,由该服务获取access_token,然后返回给浏览器。

CROS相关知识可以参考:阮一峰的日志《跨域资源共享 CORS 详解》

解决办法

自己部署一个代理服务,代码见:aishenghuomeidaoli/gh-oauth-server,已发起pull request。