WIP-CHECKPOINT[auth-refactor]: 固化工程师崩溃前部分成果 + 同树其他未提交WIP(仅源码,不含密钥/二进制)-- 待重激活工程师续作

This commit is contained in:
Simon
2026-07-07 21:52:11 +08:00
parent 242c1967ff
commit fab75760e0
203 changed files with 21504 additions and 3345 deletions
+21 -9
View File
@@ -205,10 +205,14 @@ class QrcodeService:
优先使用 settings.wecom_sso_callback_base + /api/auth_qrcode/scan 拼接完整 URL。
企微要求 redirect_uri 必须是完整的可信域名 URL,不能用相对路径。
如果未配置 wecom_sso_callback_base,则抛出异常提醒配置
如果未配置 wecom_sso_callback_base,则尝试读取环境变量作为兜底
"""
import os
# 优先使用 wecom_sso_callback_base 构建完整 URL
callback_base = getattr(settings, "wecom_sso_callback_base", "")
if not callback_base:
# 兜底: 读环境变量
callback_base = os.getenv("WECOM_SSO_CALLBACK_BASE", "")
if callback_base:
# 去除末尾斜杠,确保路径正确拼接
base = callback_base.rstrip("/")
@@ -249,25 +253,28 @@ class QrcodeService:
logger.warning(f"扫码失败: ticket 已过期或不存在 ticket={ticket[:8]}...")
raise ValueError("扫码票据已过期或不存在")
# 2. 获取用户身份
# 2. 获取用户身份(含企微头像 URL,供 confirm 时落库)
employee_id = ""
name = ""
avatar = ""
if _dev_mode_enabled():
# dev 模式: 用预设 dev 用户
# 提取 code 中的 userid(约定 dev 模式下 code 形如 "dev:dev-user-001")
employee_id, name = self._dev_extract_user(code)
employee_id, name, avatar = self._dev_extract_user(code)
logger.info(
f"[DEV] 扫码回调模拟: ticket={ticket[:8]}..., "
f"employee_id={employee_id}, name={name}"
)
else:
# 生产模式: 调企微 OAuth API
employee_id, name = await self._fetch_oauth_user(code)
employee_id, name, avatar = await self._fetch_oauth_user(code)
# 3. 写 Redis 扫码结果(TTL 120s,等待 confirm 端点消费)
# avatar 一并写入,confirm 时无需再次调用企微 API 即可同步头像
scan_payload = {
"employee_id": employee_id,
"name": name,
"avatar": avatar,
"scanned_at": datetime.now().isoformat(),
}
await self.redis.setex(
@@ -303,9 +310,9 @@ class QrcodeService:
"""
# dev 模式预设用户表(与 dev_auth.py 保持一致)
DEV_USERS = {
"dev-user-001": ("dev-user-001", "张三(普通员工)"),
"dev-agent-001": ("dev-agent-001", "李四(IT 坐席)"),
"dev-admin-001": ("dev-admin-001", "钱七(系统管理员)"),
"dev-user-001": ("dev-user-001", "张三(普通员工)", ""),
"dev-agent-001": ("dev-agent-001", "李四(IT 坐席)", ""),
"dev-admin-001": ("dev-admin-001", "钱七(系统管理员)", ""),
}
if code.startswith("dev:"):
@@ -313,10 +320,11 @@ class QrcodeService:
if user_id in DEV_USERS:
return DEV_USERS[user_id]
# 兜底:用 settings 默认 dev 用户
# 兜底:用 settings 默认 dev 用户(dev 模式无企微头像,avatar 留空)
return (
settings.dev_default_userid,
settings.dev_default_name,
"",
)
async def _fetch_oauth_user(self, code: str) -> tuple[str, str]:
@@ -350,7 +358,8 @@ class QrcodeService:
user_info = await wecom.get_user_info(user_id)
name = user_info.get("name", "")
return user_id, name
avatar = user_info.get("avatar", "")
return user_id, name, avatar
finally:
try:
await wecom.close()
@@ -408,6 +417,7 @@ class QrcodeService:
employee_id = scan_data.get("employee_id", "")
name = scan_data.get("name", "")
avatar = scan_data.get("avatar", "")
if not employee_id:
raise ValueError("扫码数据缺少 employee_id")
@@ -432,6 +442,7 @@ class QrcodeService:
employee_id=employee_id,
name=name,
roles=roles,
avatar=avatar,
login_source="qrcode",
)
@@ -458,6 +469,7 @@ class QrcodeService:
"token": token,
"employee_id": employee_id,
"name": name,
"avatar": avatar,
"roles": roles,
"require_otp": require_otp,
}