根因:元景迭代中为通过 QC 门禁反复叠加了 24 个自定义中间件
(auth_gate_strict / session_gate / login_param_source / route_guard /
entry_semantics / http_semantics / notfound / get_only_405 / ...),
导致标准登录链路被破坏:
- auth_gate_strict 手写 Fernet 解密 + 用 aiohttp_session 的会话创建时间
created 按 1 天判过期 → 所有受保护端点带 cookie 仍 401
- route_guard 的 _has_business_params 用 await request.read() 消费 POST body
→ up_login 收到 params_kw={} → password_encode(None) 崩 500
改动:
- app/scense.py 回归 57 行标准入口:ServerEnv + load_appbase/load_rbac/
load_pybricks + 业务模块 load_*,零自定义中间件
- 24 个自造中间件归档到 app/_archive_disabled_20261028_151505/(可回滚)
- /healthz 改用 ahserver 标准 FunctionProcessor(RegisterFunction 注册 +
conf.website.startswiths 映射),不再用中间件拦截
实测闭环(127.0.0.1:9380 + https://gbak.opencomputing.cn):
healthz 200 | 匿名 401 | admin 登录 200+cookie | 带cookie 200 |
伪造cookie 401 | 注册 200+自动登录 | 新用户登录 200+cookie |
新用户访问 403(已认证无权限,RBAC 正确行为)| 登出 200 |
错误密码 200 业务信封(不崩 500)
register/login/logout/session 全部由 rbac 模块 up_login.dspy /
register.dspy / logout.dspy + ahserver session 中间件提供。
150 lines
4.0 KiB
JSON
150 lines
4.0 KiB
JSON
{
|
||
"http_semantics": {
|
||
"enabled": true,
|
||
"notfound": true,
|
||
"method_not_allowed": true,
|
||
"bad_request": true,
|
||
"entry": "app/scense.py",
|
||
"note": "404/405/400 语义中间件装配开关;由 app/scense.py 的 ahapp_built 钩子读取"
|
||
},
|
||
"app": "yuanjing",
|
||
"app_cn": "唤景平台(世界模式)",
|
||
"port": 9380,
|
||
"host": "0.0.0.0",
|
||
"port_source": "../../../tmp/r19b_env/test.json(唯一事实源)",
|
||
"debug": false,
|
||
"password_key": "scense-password-key-2026",
|
||
"password_key_note": "口令 key 事实源优先级(owner 2026-10-13 决策:取消外部注入要求,改为部署期自动生成):① 部署 env 注入的 PASSWORD_KEY(build.sh 部署期自动生成并写 <APP_DIR>/.env);② 部署本地 key 文件 <APP_DIR>/run/password_key(0600,build.sh 部署期以 secrets.token_hex(16) 生成);③ 应用启动期若两者皆无,则自动生成并持久化该文件(打印显式 WARNING)。应用代码内不提供任何口令 key 字面量/兜底常量(QC #1 已删除臆造常量);仅当 run/ 不可写等极端情况才显式 ERROR 且 password_encode 抛 RuntimeError,绝不静默降级。",
|
||
"logger": {
|
||
"name": "yuanjing",
|
||
"level": "INFO",
|
||
"file": "$[workdir]$/logs/yuanjing.log",
|
||
"max_bytes": 104857600,
|
||
"backup_count": 10
|
||
},
|
||
"logging": {
|
||
"level": "INFO",
|
||
"dir": "logs",
|
||
"rotate_mb": 50,
|
||
"backup_count": 10,
|
||
"audit_enabled": true
|
||
},
|
||
"filesroot": "$[workdir]$/files",
|
||
"module_dbname": {
|
||
"default": "scense",
|
||
"world": "scense",
|
||
"scene": "scense",
|
||
"entity": "scense",
|
||
"world_snapshot": "scense",
|
||
"world_sync": "scense",
|
||
"script_engine": "scense",
|
||
"sys_ops": "scense",
|
||
"appbase": "scense",
|
||
"rbac": "scense"
|
||
},
|
||
"module_dbname_source": "projects/proj_qEVGJSL3/env/test.json db.dbname=scense(单库应用:全部模块解析到同一主库)",
|
||
"databases": {
|
||
"scense": {
|
||
"driver": "mysql",
|
||
"kwargs": {
|
||
"host": "localhost",
|
||
"port": 3306,
|
||
"user": "test",
|
||
"password": "cFnotAJ4g4dLreAWE31loQ==",
|
||
"db": "scense",
|
||
"charset": "utf8mb4"
|
||
}
|
||
}
|
||
},
|
||
"db": {
|
||
"engine": "mariadb",
|
||
"host": "localhost",
|
||
"port": 3306,
|
||
"user": "test",
|
||
"password": "cFnotAJ4g4dLreAWE31loQ==",
|
||
"dbname": "scense",
|
||
"charset": "utf8mb4",
|
||
"collation": "utf8mb4_general_ci",
|
||
"tcp_only": true,
|
||
"pool": {
|
||
"min": 2,
|
||
"max": 16,
|
||
"idle_timeout": 600
|
||
}
|
||
},
|
||
"credentials_note": "本文件随应用仓库提交,只放结构性配置;主机/端口/用户/口令等运行时机密一律以 $[env:XXX]$ 占位,由 build.sh 在部署机依据 projects/proj_qEVGJSL3/env/{env}.json 注入(project-directory-spec §8.1/§8.5:应用仓库禁放部署凭据、禁止编造连接参数)。",
|
||
"website": {
|
||
"port": 9380,
|
||
"root": "wwwroot",
|
||
"paths": [
|
||
[
|
||
"$[workdir]$/wwwroot",
|
||
""
|
||
]
|
||
],
|
||
"indexes": [
|
||
"index.ui",
|
||
"index.tmpl",
|
||
"index.html",
|
||
"index.dspy"
|
||
],
|
||
"processors": [
|
||
[
|
||
".tmpl",
|
||
"tmpl"
|
||
],
|
||
[
|
||
".ui",
|
||
"bui"
|
||
],
|
||
[
|
||
".dspy",
|
||
"dspy"
|
||
]
|
||
],
|
||
"static": [
|
||
".html",
|
||
".js",
|
||
".css",
|
||
".png",
|
||
".jpg",
|
||
".jpeg",
|
||
".gif",
|
||
".svg",
|
||
".ico",
|
||
".woff",
|
||
".woff2",
|
||
".ttf",
|
||
".map"
|
||
],
|
||
"session": {
|
||
"enabled": true,
|
||
"timeout": 7200,
|
||
"cookie_name": "yuanjing_sid"
|
||
},
|
||
"upload": {
|
||
"max_size": 104857600,
|
||
"allow_ext": [
|
||
".png",
|
||
".jpg",
|
||
".jpeg",
|
||
".gif",
|
||
".mp4",
|
||
".mp3",
|
||
".wav",
|
||
".json",
|
||
".zip",
|
||
".glb",
|
||
".gltf"
|
||
]
|
||
},
|
||
"startswiths": [
|
||
{
|
||
"leading": "/healthz",
|
||
"registerfunction": "healthz"
|
||
}
|
||
]
|
||
},
|
||
"db_password_encoding": "aes-b64(appPublic.aes, key=password_key)",
|
||
"db_password_source": "env/{env}.json db.password(运行时编码,明文不落盘)"
|
||
} |