# ============================================================================= # 企微IT智能服务台 — 环境门禁(三端认证重构 AUTH-01) # ============================================================================= # 说明:根据 app_env 判断当前是否生产环境,统一控制以下强校验的启用: # 1. 企微 WebView(wxwork)UA 校验 # 2. 管理后台 IP 白名单 # 3. 真实企微 OAuth2 静默授权 # # 设计原则(决策来源:system_design.md 环境门禁矩阵): # - 仅 production 环境启用上述强校验 # - dev / test / 未配置 一律视为非生产,跳过强校验,方便本地开发 # # 使用方式: # from app.utils.env_gating import is_production, ip_in_whitelist # if is_production(): # ... # ============================================================================= from ipaddress import ip_address, ip_network from typing import List, Optional from app.config import settings def is_production() -> bool: """判断是否生产环境。 仅当 app_env == "production" 时返回 True。 其他值(dev / test / 空字符串)一律视为非生产环境, 从而跳过 UA 校验 / IP 白名单 / 真实 OAuth 等强校验。 Returns: bool: True=生产环境,False=非生产环境 """ return (settings.app_env or "dev").strip().lower() == "production" def _parse_allowed_ips(raw: Optional[str]) -> List[str]: """把逗号分隔的 IP / 网段字符串解析为去空白后的列表。 Args: raw: 形如 "117.147.35.138,218.75.34.87,10.240.0.0/16" 的字符串 Returns: List[str]: 非空条目列表(已去除首尾空白) """ if not raw: return [] return [item.strip() for item in raw.split(",") if item.strip()] def ip_in_whitelist(client_ip: str, allowed: Optional[str] = None) -> bool: """判断客户端 IP 是否在白名单内(支持 CIDR 网段)。 匹配规则: - 白名单为空 → 保守拒绝(不开放) - client_ip 格式非法 → 拒绝 - 白名单条目含 "/" → 按 CIDR 网段匹配(ip_network, strict=False) - 白名单条目为单 IP → 精确相等匹配 Args: client_ip: 客户端 IP(如 "10.240.1.5") allowed: 白名单字符串(逗号分隔,支持 CIDR)。 缺省时读取 settings.admin_allowed_ips。 Returns: bool: True=在白名单内,False=不在 / 格式非法 / 白名单为空 """ if not client_ip: return False allowed_raw = allowed if allowed is not None else settings.admin_allowed_ips entries = _parse_allowed_ips(allowed_raw) if not entries: # 白名单为空 → 保守策略:不开放任何 IP return False try: client = ip_address(client_ip) except ValueError: # 客户端 IP 格式非法 → 拒绝 return False for entry in entries: try: if "/" in entry: # CIDR 网段匹配(如 10.240.0.0/16) network = ip_network(entry, strict=False) if client in network: return True else: # 单 IP 精确匹配 if client == ip_address(entry): return True except ValueError: # 单个白名单条目格式非法 → 跳过,继续匹配其他条目 continue return False