Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

immatt2015/opt_auth

Repository files navigation

opt_auth —— 基于 OpenResty 的用户名/密码 + TOTP 双因素认证组件

项目概述

  • 提供登录页(用户名、密码、TOTP 验证码),认证成功后颁发 JWT 写入 Cookie。
  • 后续请求通过校验 Cookie 中的 JWT、来源 IP 与本地用户缓存决定是否放行。
  • 适合内网或简单后台的统一接入鉴权,作为 OpenResty/Nginx 的 Lua 模块使用。

主要能力

  • 登录表单输出与友好的提示信息。
  • 用户密码校验(当前为 MD5,比对共享缓存中的用户信息)。
  • TOTP 校验(兼容 Google Authenticator 等),支持生成 otpauth/二维码 URL。
  • JWT 签发与校验:包含 role、user、ip、sec 及 iat/exp 字段;Cookie 含 HttpOnly、SameSite=Lax,HTTPS 下追加 Secure。
  • 用户信息热加载:从 JSON 文件加载到 lua_shared_dict 缓存。

快速开始

  1. 环境准备
    • OpenResty(提供 ngx、ngx.hmac_sha1、lua_shared_dict 等)
    • Lua 依赖:cjson、resty.jwt(可通过 opm 安装)
  2. 放置代码
    • 将本仓库的 lib 目录加入 lua_package_path,或通过 opm 安装发布包。
  3. 配置 Nginx(见下方"示例配置")
  4. 准备用户数据 JSON 文件(见下方"用户数据示例")

Nginx/OpenResty 示例配置

worker_processes 1;
events { worker_connections 1024; }
http {
 # 共享字典用于缓存用户信息
 lua_shared_dict jwt 10m;
 # 调整 lua 包路径(按实际路径)
 lua_package_path "/path/to/opt_auth/lib/?.lua;;";
 init_worker_by_lua_block {
 -- 周期性加载用户数据到共享缓存
 local access = require("otp_access")
 -- 每 30 秒从指定 JSON 文件刷新用户信息
 local ok, err = ngx.timer.every(30, access.reload_user_info, "/etc/openresty/users.json")
 if not ok then
 ngx.log(ngx.ERR, "failed to start reload_user_info timer: ", err)
 end
 }
 server {
 listen 8080;
 server_name localhost;
 # 仅示例:设置 JWT 签名密钥
 set $jwt_key "CHANGE_ME_TO_A_STRONG_SECRET";
 location / {
 access_by_lua_block {
 local access = require("otp_access")
 -- 调用鉴权;通过时返回 0,失败将输出登录页并结束请求
 access.do_auth(ngx.var.jwt_key)
 }
 proxy_pass http://127.0.0.1:9000; # 业务上游
 }
 }
}

用户数据示例(/etc/openresty/users.json)

{
 "alice": {
 "passwd": "e10adc3949ba59abbe56e057f20f883e", // 123456 的 MD5,仅示例
 "totp_key": "JBSWY3DPEHPK3PXP", // Base32 密钥
 "role": "admin"
 },
 "bob": {
 "passwd": "202cb962ac59075b964b07152d234b70", // 123 的 MD5,仅示例
 "totp_key": "NB2W45DFOIZA", // Base32 密钥
 "role": "user"
 }
}

注意:当前实现使用 MD5 校验密码,建议仅用于演示或内网。生产建议升级为带盐的强哈希(如 bcrypt/argon2),并提供兼容迁移。

TOTP 使用说明

  • 生成 otpauth URL 或二维码 URL(供首次绑定到 Authenticator):
local otp = require("otp")
local t = otp.totp_init("JBSWY3DPEHPK3PXP")
local url = t:get_url("MyService", "alice") -- otpauth://totp/alice?secret=...&issuer=MyService
local qr = t:get_qr_url("MyService", "alice") -- Google Chart 的二维码链接

模块接口速览

  • 入口模块:lib/otp_access.lua
    • req_auth(origin_uri, tip):输出登录页
    • remove_auth():清除 auth Cookie
    • do_auth(jwt_key):执行鉴权逻辑(Cookie/JWT 校验、表单校验、TOTP 校验、签发 JWT)
    • reload_user_info(premature, user_info_path):从 JSON 文件加载用户信息至共享缓存
  • TOTP 模块:lib/otp.lua
    • totp_init(secret_key):构造 TOTP 对象
    • verify_token(code):校验 6 位动态码
    • get_url(issuer, account) / get_qr_url(issuer, account):生成绑定链接

安全提示

  • 已在代码内设置 Cookie 的 HttpOnly 与 SameSite=Lax,并在 HTTPS 下追加 Secure。
  • JWT 增加 iat/exp 字段,默认有效期 2 小时;如需更严格策略,可在网关或下游对 exp/nbf 再次核验。
  • 绑定 IP 校验:JWT 中携带 ip,并在校验时与请求来源比对;若有代理,请正确传递并信任 X-REAL-IP/X_FORWARDED_FOR

版本与发布

  • 包信息见 dist.ini,主模块为 lib/otp_access.lua。***

如何使用

  1. 获取代码并准备用户数据
  • 克隆/下载本项目,将 conf/users.json 按需修改;字段说明见"用户数据示例"。
  • 如需生成新的 Base32 TOTP 密钥,可在 OpenResty REPL 中:
resty -e 'local otp=require("otp"); local t=otp.totp_init(nil); print(t.key)'
  1. 使用 Docker Compose 运行
  • 直接在项目根目录执行:
docker-compose up --pull always -d
  1. 关键文件说明
  • docker-compose.yml:启动 OpenResty;容器启动时通过 opm 安装 lua-resty-jwt
  • conf/nginx.conf:最小可运行配置,映射 8080 端口,周期性加载 conf/users.json
  • lib/:鉴权逻辑与 TOTP 实现。
  1. 在自有环境集成
  • lib 放入 lua_package_path,并在 access_by_lua_block 中调用:
local access = require("otp_access")
access.do_auth("YOUR_JWT_SECRET")
  • init_worker_by_lua* 中周期性调用 reload_user_info 加载用户数据:
local ok, err = ngx.timer.every(30, access.reload_user_info, "/path/to/users.json")

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /