feat(gateway): 登录成功后更新 Users.last_login(v0.5.1)

启用 handleLogin 中被注释的 last_login 更新:经 DbC::call_msg 以
"$now" 哨兵(db 日期适配层转为服务端 UTC 时间)写入,失败按惯例
THROW_EX_CUSTOM 抛 500 由 wrapper 统一处理。README 版本节同步
(原仍停留在 0.3.0-security)。
This commit is contained in:
qing committed 2026-07-28 23:31:20 +08:00
1 parent 19d5b65625
commit b07dbf2da5
3 files changed
+21 -19

No files matched your search

+1 -1
View File
@@ -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)的图形验证码代理路由。
+4 -2
View File
@@ -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++`)
+16 -16
View File
@@ -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 <sstream>
@@ -811,21 +811,21 @@ http::response<http::string_body> 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");
/* 生成令牌 */