diff --git a/README.md b/README.md index 19d3ef6..f6b426c 100755 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ - 内部 HTTP 服务,默认监听 127.0.0.1:8443,不再承载 TLS(TLS 已由 WAF 终止)。 - 通过 `Server.tls = on/off` 配置切换 HTTPS/HTTP 模式([example.ini](gateway/example.ini)),独立部署时仍可启用 TLS。 - **密码安全**:PBKDF2-HMAC-SHA256(10 万轮 + 16 字节随机盐),密码强度校验(8+ 字符、4 类中至少 3 类),常数时间比较防 timing attack。 -- **用户存储**:用户数据通过 pymsg/TCP 调用 `db:8005`(`DbC::call_msg`)存取,不再直连本地 SQLite。 +- **用户存储**:用户数据通过 pymsg/TCP 调用 `db:8005`(`DbC::call_msg`)存取,不再直连本地 SQLite;登录成功即更新 `Users.last_login`(`"$now"` 哨兵)。 - **Token 机制**:`Base64(payload) + "_" + RSA-Sign(payload)`,默认 1 小时过期,验签通过才放行;RSA 密钥对启动时内存生成,重启后旧 Token 全部失效。 - **Cookie 认证**:登录成功同时签发 `HttpOnly + Secure + SameSite=Lax` 的 `q4_token` Cookie;代理时无 `Authorization` 头则回退读 Cookie 验签,并向下游注入 `Authorization: Bearer`(下游零改动);`POST /logout` 清除 Cookie。公开目标(`Proxy.default`)不做凭证校验,避免旧 Cookie 影响公开页面。 - **CAPTCHA**:`/captcha` 接口生成验证码(5 分钟过期、一次性使用),登录与注册均可选启用;`GET /captcha/image` 为 captcha 服务(pymsg/TCP :8009)的图形验证码代理路由。 diff --git a/gateway/README.md b/gateway/README.md index 44504e1..c4d999c 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -226,12 +226,14 @@ gateway/ ## 版本 -`0.3.0-security`(见 [src/main.cpp:27](src/main.cpp#L27))。启动时打印: +`0.5.1`(见 [src/main.cpp:29](src/main.cpp#L29))。启动时打印: ``` -Gateway 0.3.0-security started (PBKDF2 + CAPTCHA + RateLimit) +Gateway 0.5.1 started ``` +近期变更:登录成功后通过 db 更新 `Users.last_login`(`"$now"` 哨兵,db 日期适配层转为服务端当前 UTC 时间;更新失败经 THROW_EX_CUSTOM 抛 500,与其他步骤一致)。 + ## 依赖 - C++20(`g++`) diff --git a/gateway/src/main.cpp b/gateway/src/main.cpp index 0e88a60..fbf8ce2 100644 --- a/gateway/src/main.cpp +++ b/gateway/src/main.cpp @@ -26,7 +26,7 @@ using namespace qing; namespace json = boost::json; namespace po = boost::program_options; -constexpr const char *_VER = "0.5.0"; +constexpr const char *_VER = "0.5.1"; ////////////////////////////////// #include @@ -811,21 +811,21 @@ http::response handleLogin( //stmt_upd.bind_text(1, username); //stmt_upd.step(); // - // 新版调用db模块 无法通过DB上传时间戳目前 - //json::value jv_upd = { - // {"action", "update"}, - // {"table", "Users"}, - // {"values", json::object{ - // {"last_login", LocalTime::getCurrent()}, - // }}, - // {"where", json::object{ - // {"username", username}, - // }} - //}; - //auto jv_db_r = DbC::call_http(jv_upd); - //auto obj_r = jv_db_r.as_object(); - //auto success = obj_r["success"].as_bool(); - //if (!success) THROW_EX_CUSTOM(HttpException, 2102, json::serialize(jv_db_r)+"Login (Update Step) Failed", 500, "/login"); + // 新版调用db模块:values 中的 "$now" 哨兵由 db 日期适配层替换为服务端当前 UTC 时间 + //(此前因 db 无法处理日期列而注释,dbv2 增加 _coerce_value 后可用)。 + json::value jv_upd = { + {"action", "update"}, + {"table", "Users"}, + {"values", json::object{ + {"last_login", "$now"}, + }}, + {"where", json::object{ + {"username", username}, + }} + }; + auto jv_upd_r = DbC::call_msg(jv_upd); + if (!jv_upd_r.as_object()["success"].as_bool()) + THROW_EX_CUSTOM(HttpException, 2102, "Login (Update Step) Failed", 500, "/login"); /* 生成令牌 */