# ============================================================================= # 企微IT智能服务台 — 企微环境检测工具 # ============================================================================= # 说明:企微环境检测工具,提供统一的 User-Agent 检测逻辑 # ============================================================================= import re from typing import Optional from fastapi import Request from app.utils.response import AppException # 企微浏览器 UA 正则 # 企微桌面端 UA 示例:Mozilla/5.0 ... wxwork/4.1.22 ... # 企微移动端 UA 示例:Mozilla/5.0 (iPhone ... MicroMessenger/7.x ... wxwork/3.x ... _WEWORK_UA_RE = re.compile(r"wxwork", re.IGNORECASE) # 允许跳过检测的主机名(本地开发环境) _LOCALHOST_HOSTS = {"localhost", "127.0.0.1", "0.0.0.0"} def is_localhost_request(request: Request) -> bool: """检查请求是否来自本地开发环境。 Args: request: FastAPI Request 对象 Returns: True 表示是本地请求,应跳过企微环境检测 """ host = request.headers.get("host", "") # 提取主机名(去掉端口) hostname = host.split(":")[0] if host else "" return hostname in _LOCALHOST_HOSTS def check_wecom_ua(request: Request) -> Optional[str]: """检测请求是否来自企微 WebView。 本地开发环境(localhost/127.0.0.1)跳过检测。 Args: request: FastAPI Request 对象,用于读取 User-Agent 和 Host Returns: None 表示检测通过,返回具体的错误信息表示检测失败 Raises: AppException: 非企微环境时抛出 400 错误 """ # 本地开发环境跳过检测 if is_localhost_request(request): return None ua = request.headers.get("user-agent", "") if not _WEWORK_UA_RE.search(ua): return "请在企业微信中访问此服务" return None def require_wecom_ua(request: Request) -> None: """校验请求 User-Agent 是否来自企微 WebView。 生产环境下,非企微环境的请求直接拒绝。 本地开发(localhost / 127.0.0.1)跳过检测,方便调试。 Args: request: FastAPI Request 对象,用于读取 User-Agent 和 Host Raises: AppException: 非企微环境时抛出 400 错误 """ error_msg = check_wecom_ua(request) if error_msg: raise AppException(4003, error_msg)