From e29fce4012ab06dcd92d02c2919c2f9e76e06d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=BF=E4=BA=91=E7=A7=8B=E6=9C=88?= <15273589815@163.com> Date: Fri, 11 Sep 2026 21:26:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=99=BB=E5=BD=95=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=8F=B0=EF=BC=9A=E4=B8=80=E4=B8=AA=E8=AE=B0=E4=BA=8B?= =?UTF-8?q?=E6=9C=AC=E7=BA=A7=E5=88=AB=E7=9A=84=E5=89=8D=E7=AB=AF=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E6=9D=A5=E5=9C=A8=E6=B5=8F=E8=A7=88=E5=99=A8=E9=87=8C?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tools/login_console.py —— 浏览器打开 http://127.0.0.1:8099 即可测。 与 chat_console.py 的关键差别:**它走真实登录接口**(POST /api/v1/auth/tokens)拿令牌, 而不是自己签。chat_console 是当初还没有登录接口时的权宜做法,这个测的是真链路。 页面能做的: - 三个快捷填充按钮(客户 cust_t/123456、员工 risk_t/666666、管理员 admin_t/88888888); - 登录后显示用户、角色标签、data_scope、令牌有效期(令牌只显示前 24 字符); - 按角色列出可调的**只读**接口按钮(我的画像 / 风控概览 / 预警列表 / 角色清单 / 管理视角看某人的身份),一眼核对"登录给的 roles"与"接口实际放行"是否一致; - 把真实状态码与响应 JSON 原样摊在页面上,并写明 401 涵盖三种原因、429 是登录限流。 实现上不动 app/ 一个字节:内层用 create_app(),本进程只做两件事 —— 提供静态页、 把 /api/* 同源转发(httpx.ASGITransport 进程内调用,不起第二个服务)。同源转发避开 CORS, 也免得浏览器直连主服务;只监听 127.0.0.1,私钥始终留在服务端。 实测:页面 200;通过代理用 admin_t 登录拿到真实 JWT(sub=9003);错密码 401。 顺带说明一条边界变化:docs/24 当初拒绝"给底座加 dev token 端点",理由是那种端点等于把 **任意身份**开放给任何能访问服务的人。现在有了密码校验,浏览器拿令牌不再等于 "谁都能冒充任何人",那条顾虑已消除 —— 所以这个页面不是绕过安全设计,而是设计补齐后的正常用法。 --- tools/login_console.py | 267 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 tools/login_console.py diff --git a/tools/login_console.py b/tools/login_console.py new file mode 100644 index 0000000..347959c --- /dev/null +++ b/tools/login_console.py @@ -0,0 +1,267 @@ +"""登录测试台:一个记事本级别的前端,用来在浏览器里验证登录接口。 + +浏览器打开 **http://127.0.0.1:8099**(可用 `--port` 改)。 + +## 它做什么 / 不做什么 + +- **走真实登录接口**(`POST /api/v1/auth/tokens`)拿令牌,和前端将来要做的一模一样。 + 与 `tools/chat_console.py` 不同:那个是当初还没有登录接口时自己签令牌的权宜做法, + 这个测的就是真链路。 +- 拿到令牌后可以按角色调几个**只读**接口,直接把状态码与响应 JSON 摊在页面上 —— + 方便确认"登录给的 roles 与接口实际放行的权限是否一致"。 +- **不动 `app/` 一个字节**:内层用 `create_app()`,本进程只做两件事 —— 提供一个静态页面、 + 把 `/api/*` 同源转发给它。同源转发是为了避开 CORS,也让浏览器不必直连主服务。 +- 只监听 `127.0.0.1`,不出本机。私钥始终在服务端(登录是后端做的),页面只拿到令牌。 + +## 为什么现在可以做这个了 + +`docs/24` 当初拒绝"给底座加 dev token 端点",理由是那种端点等于把**任意身份**开放给 +任何能访问服务的人。现在不同了:登录接口要**校验密码**,所以浏览器拿令牌这件事 +不再等于"谁都能冒充任何人"。这条顾虑已经消除。 + +用法: + + python tools/login_console.py # 默认 8099 + python tools/login_console.py --port 9000 +""" + +from __future__ import annotations + +import argparse + +import httpx +import uvicorn +from fastapi import FastAPI, Request +from fastapi.responses import HTMLResponse, Response + +from app.main import create_app + +PAGE = """ + +
+ + +POST /api/v1/auth/tokens。密码仅用于本地演示。
+ (还没有请求)+