关于openresty的安装可以查看Linux Docker 部署openresty nginx – recallmc blog
关于poste.io可以查看Linux docker 部署poste.io+nginx – recallmc blog
1、准备相关lua脚本
captcha_api.lua
-- 验证码生成API - 单点生成
-- 生成验证码并返回JSON数据
local chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
local code = ""
for i = 1, 6 do
local rand = math.random(#chars)
code = code .. string.sub(chars, rand, rand)
end
-- 生成唯一key
local timestamp = ngx.now()
local key = "captcha_" .. ngx.md5(code .. timestamp .. math.random(1000, 9999))
-- 存储到共享内存(确保存储)
local store = ngx.shared.captcha_store
local success, err = store:set(key, code, 300) -- 5分钟过期
if not success then
ngx.log(ngx.ERR, "验证码存储失败: ", err)
ngx.status = 500
ngx.say('{"success":false,"message":"生成验证码失败"}')
return
end
-- 生成SVG图片
local width = 200
local height = 80
local svg = string.format([[
"
-- 返回JSON(包含所有数据)
local response = string.format([[
{
"success": true,
"data": {
"key": "%s",
"code": "%s",
"svg": "%s"
},
"timestamp": %f
}
]], key, code, ngx.escape_uri(svg), timestamp)
ngx.header["Content-Type"] = "application/json; charset=utf-8"
ngx.print(response)
-- 记录日志(调试用)
ngx.log(ngx.INFO, "生成验证码: key=", key, ", code=", code)
login_page.lua,这段代码有部分html代码会被识别直接显示页面,所以我放在下方文件里了,自行点击下载,然后复制到你创建的login_page.lua脚本里就行
verify_api.lua
-- 验证码验证API
local args = ngx.req.get_uri_args()
local key = args.key
local code = args.code
if not key or not code then
ngx.header["Content-Type"] = "application/json"
ngx.say('{"success": false, "message": "缺少参数"}')
return
end
-- 从共享内存获取验证码
local store = ngx.shared.captcha_store
local stored_code = store:get(key)
-- 记录日志
ngx.log(ngx.INFO, "验证请求: key=", key,
" 输入=", code,
" 存储=", stored_code or "nil",
" IP=", ngx.var.remote_addr)
if not stored_code then
ngx.header["Content-Type"] = "application/json"
ngx.say('{"success": false, "message": "验证码已过期"}')
return
end
-- 验证验证码(不区分大小写)
if string.upper(stored_code) ~= string.upper(code) then
store:delete(key)
ngx.header["Content-Type"] = "application/json"
ngx.say('{"success": false, "message": "验证码错误"}')
return
end
-- 验证成功,删除验证码
store:delete(key)
-- 创建会话
local session_id = "sess_" .. ngx.md5(key .. ngx.now() .. math.random(1000, 9999))
store:set("session_" .. session_id, "valid", 3600)
ngx.header["Content-Type"] = "application/json"
ngx.say('{"success": true, "session": "', session_id, '", "message": "验证成功"}')
将准备好的lua脚本放入指定的lua脚本目录,例如我指定的目录是/data/openresty/lua
2、修改nginx的配置
首先进入我们部署好的docker容器中
docker exec -it openresty bash
修改nginx的主要配置文件
cd /usr/local/openresty/nginx/conf
vim nginx.conf
将如下代码复制到http块中
# 必须的 lua 包路径配置
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
lua_shared_dict captcha_store 10m;
按住shift输入英文冒号,输入wq保存并退出,输入exit退出容器
将如下代码替换之前的nginx反向代理配置,注意域名替换成自己的
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
# 原有 server_name,可继续新增更多当前证书支持的域名
server_name mail.recallmc.com;
# ========== 核心API ==========
# 1. 生成验证码(同时返回图片和数据)
location = /api/captcha {
default_type application/json;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
content_by_lua_file /etc/nginx/lua/captcha_api.lua;
}
# 2. 验证验证码
location = /api/verify {
default_type application/json;
content_by_lua_file /etc/nginx/lua/verify_api.lua;
}
# ========== 页面 ==========
# 3. 登录页面(不生成验证码,只显示页面)
location = /login {
content_by_lua_file /etc/nginx/lua/login_page.lua;
}
# ========== 访问控制 ==========
# 4. 主访问控制
location / {
# 白名单
if ($uri = /login) {
break;
}
if ($uri = /api/captcha) {
break;
}
if ($uri = /api/verify) {
break;
}
# 检查认证
if ($cookie_captcha_session != "verified") {
return 302 /login;
}
# 其它配置
client_max_body_size 75M; # 允许的最大文件大小为 20MB
proxy_pass https://poste-mail;
proxy_set_header Host $host;
# real-ip
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
# websocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_read_timeout 86400;
## replace content ##
sub_filter_once off;
sub_filter '撰写新邮件' '写信';
sub_filter 'Dark mode' '深色';
sub_filter 'Light mode' '浅色';
sub_filter '[Administration]' '控制台';
sub_filter '>Administration<' '>控制台<';
sub_filter 'Trusted Senders' '可信发件人';
sub_filter 'Collected Recipients' '收件人集合';
sub_filter '' '\n.pro,.brand,.nav-sidebar p.alert{display:none !important}\n';
}
# ========== 错误页面 ==========
error_page 401 /login;
error_page 403 /login;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /404.html {
internal;
return 404 '{"error": "Not Found"}';
}
location = /50x.html {
internal;
return 500 '{"error": "Internal Server Error"}';
}
}
3、重载配置
docker exec openresty nginx -s reload

Comments NOTHING