之前不是在博客写了一篇文章嘛,写了一个关于Alist动态验证码的功能,访问Alist必须进行验证后才能进行访问,然后这个可能对小白不太友好,这里我写篇详尽文章教大家如何使用AList嵌入动态验证码

准备工作

  • 一台国内服务器
  • 已备案域名
  • 微信订阅号一个

环境准备

搭建一个Web服务器环境是创建和维护网站的基础步骤。对于有经验的开发者来说,这个过程可能已经非常熟悉了。但对于那些刚开始接触建站的朋友,建议您先去看一下如何建站

安装Node.js

Node.js是一个开源、跨平台的JavaScript运行时环境,它允许开发者在服务器端运行JavaScript代码,本程序后端就是基于Node.js编写的,如果您不了解Node.js 那您更应该仔细看这部分内容了

以我的 Debian系 主机环境为例

1,下载安装Node.js (18+版本均可)

下载地址:https://nodejs.cn/download/

或者直接执行如下命令

1
wget https://npmmirror.com/mirrors/node/v20.18.0/node-v20.18.0-linux-x64.tar.xz

下载完成后将 node-v20.18.0-linux-x64.tar.xz 解压到当前文件夹,会得到 node-v20.18.0-linux-x64

node-v20.18.0-linux-x64文件夹移动到/usr/local/node 目录中,并重命名为node

2,配置 Node.js 环境

编辑/etc/profile 文件

最底部添加如下内容

1
2
export NODE_HOME=/usr/local/node
export PATH=$NODE_HOME/bin:$PATH

保存之后执行 source /etc/profile 使其生效。

3,配置镜像加速

由于某些原因, npmjs.com 在国内的访问速度很不稳定。 所以我们可以考虑用国内的镜像网站地址替换,执行如下命令,配置为国内镜像源

1
npm config set registry https://registry.npmmirror.com
4,克隆仓库

我将这个项目的代码上传到了GitHub,可直接从github获取

地址:Alist_Dynamic_verification: Alist AList嵌入动态验证码工具 (github.com)

5,安装依赖
1
2
cd Alist_Dynamic_verification
npm install
6,配置微信订阅号相关信息

编辑 .env 配置相关信息(后面配置也可以)

1
2
3
4
5
6
7
WECHAT_APPID=
WECHAT_SECRET=
WECHAT_TOKEN=
ENCODING_AES_KEY=
PORT=4000 # 后端运行端口,对接微信
VERIFY_PORT=4001 # 验证接口的端口,对接前端验证验证码用的
# 端口可以不定义 默认就是上面那俩
7,启动
1
node run serve
8,配置反向代理

因为微信公众号强制要求使用HTTP/HTTPS端口,这里以Nginx为例,配置反向代理

我这里用了两个域名,例如;

  • test.example.com(用于对接微信公众平台)
  • verify.example.com(用于验证验证码的)

nginx配置文件如下

test.example.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 80;
server_name test.example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
server_name test.example.com;
# SSL 配置
ssl_certificate /etc/ssl/certs/certificate.crt;
ssl_certificate_key /etc/ssl/private/private_key.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://localhost:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

verify.example.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 80;
server_name verify.example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
server_name verify.example.com;
# SSL 配置
ssl_certificate /etc/ssl/certs/certificate.crt;
ssl_certificate_key /etc/ssl/private/private_key.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://localhost:4001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

二合一配置

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
server {
listen 80;
server_name test.example.com;

return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name test.example.com;

ssl_certificate /etc/ssl/certs/certificate.crt;
ssl_certificate_key /etc/ssl/private/private_key.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://localhost:4000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /verify/ { # 将 /verify/ 路径的请求转发到 4001 端口
proxy_pass http://localhost:4001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
9、公众号配置

如上图所示,服务器地址(URL) 配置为 http://你的域名.com/eventCall/,并配置好其他参数即可

10,开机自动运行(systemd)

/etc/systemd/system/目录创建一个service文件, 定义如下内容

1
2
3
4
5
6
7
8
9
10
11
12
[Unit]
Description=Alist_Dynamic_verification
After=network.target

[Service]
ExecStart=/usr/local/node/bin/npm run serve # npm全路径,按照你的安装位置修改
WorkingDirectory= # 你的项目目录
# Environment=NODE_ENV=production
Restart=always

[Install]
WantedBy=multi-user.target

完了 daemon-reload一下 enable --now 运行服务就可以了

Alist嵌入代码
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<script disable-devtool-auto src='https://cdn.jsdelivr.net/npm/disable-devtool'></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>

<script>
document.addEventListener('keydown', function(event) {
if (event.key === 'F12' || (event.ctrlKey && event.shiftKey && ['I', 'J', 'C'].includes(event.key.toUpperCase()))) {
event.preventDefault();
}
});

document.addEventListener("DOMContentLoaded", function() {
promptPassword("success", "请输入验证码以继续访问");
});

// 验证验证码函数
function validateCaptcha(captcha) {
const xhr = new XMLHttpRequest();
xhr.open("POST", "验证接口, true);
xhr.setRequestHeader("Content-Type", "application/json");

xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
try {
const response = JSON.parse(xhr.responseText);
if (xhr.status === 200 && response.code === 200) {
welcomeUser();
} else {
swal("错误", response.msg || "验证码错误,请重试", "error").then(() => {
promptPassword("error", "请重新输入验证码");
});
}
} catch (e) {
console.error("JSON 解析错误:", e);
swal("错误", "响应格式不正确,请稍后重试", "error").then(() => {
promptPassword("error", "请重新输入验证码");
});
}
}
};

xhr.send(JSON.stringify({ code: captcha }));
}

// 提示输入验证码的函数
function promptPassword(icon, title) {
swal({
title: title,
text: "请确认您已获取正确的验证码。请点击下方按钮关注我们的微信公众号以获取验证码。",
closeOnClickOutside: false,
icon: icon,
buttons: {
confirm: {
text: "确认提交",
value: "confirm",
className: "custom-swal-button swal-button--confirm"
},
getCode: {
text: "微信公众号",
value: "get_code",
className: "custom-swal-button swal-button--copy"
}
},
content: {
element: "input",
attributes: {
placeholder: "请输入验证码",
type: "text",
style: "width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px;"
}
}
})
.then((value) => {
if (value === '') {
promptPassword("warning", "请输入正确的验证码");
} else if (value === "get_code") {
showWeChatCode();
} else if (!/^\d{6}$/.test(value)) {
promptPassword("warning", "验证码格式不正确,请输入6位数字");
} else {
validateCaptcha(value);
}
});
}

// 显示微信公众号二维码
function showWeChatCode() {
swal({
title: "关注微信公众号获取验证码",
text: "请扫描以下二维码关注我们的微信公众号以获取验证码。",
icon: "info",
closeOnClickOutside: false,
content: {
element: "img",
attributes: {
src: "公众号图片",
style: "width: 100%; height: auto; border-radius: 4px;"
}
},
buttons: {
confirm: {
text: "返回输入",
value: "confirm",
className: "custom-swal-button swal-button--confirm"
}
}
}).then(() => {
promptPassword("info", "请输入验证码以继续访问");
});
}

// 欢迎用户函数
function welcomeUser() {
swal("欢迎!", {
icon: "success",
buttons: false,
timer: 1000, //1秒后自动消失
});
}


// 防止查看页面源代码
window.onbeforeunload = function() {
return "您确定要离开此页面吗?";
};

// 检测并阻止右键菜单
window.addEventListener('contextmenu', function(event) {
event.preventDefault();
}, false);

// 检测并阻止选中文本
window.addEventListener('selectstart', function(event) {
event.preventDefault();
}, false);
</script>