初始提交
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
from fastapi import Request
|
||||
|
||||
from config.env import AppConfig
|
||||
|
||||
|
||||
class ClientIPUtil:
|
||||
"""
|
||||
客户端IP提取工具
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_client_ip(cls, request: Request) -> str:
|
||||
"""
|
||||
获取客户端真实IP
|
||||
|
||||
仅当请求来源命中可信代理列表,且可信代理跳数大于0时,才会解析
|
||||
X-Forwarded-For / X-Real-IP 请求头;否则回退到直接连接来源地址。
|
||||
|
||||
:param request: 当前请求对象
|
||||
:return: 客户端IP
|
||||
"""
|
||||
remote_addr = request.client.host if request.client else 'unknown'
|
||||
if AppConfig.app_trusted_proxy_hops <= 0:
|
||||
return remote_addr
|
||||
if not cls._should_trust_proxy_headers(remote_addr):
|
||||
return remote_addr
|
||||
|
||||
forwarded_for = request.headers.get('X-Forwarded-For', '')
|
||||
if forwarded_for:
|
||||
forwarded_chain = [item.strip() for item in forwarded_for.split(',') if item.strip()]
|
||||
if forwarded_chain:
|
||||
if len(forwarded_chain) > AppConfig.app_trusted_proxy_hops:
|
||||
return forwarded_chain[-(AppConfig.app_trusted_proxy_hops + 1)]
|
||||
return forwarded_chain[0]
|
||||
|
||||
real_ip = request.headers.get('X-Real-IP', '').strip()
|
||||
if real_ip:
|
||||
return real_ip
|
||||
|
||||
return remote_addr
|
||||
|
||||
@classmethod
|
||||
def _should_trust_proxy_headers(cls, remote_addr: str) -> bool:
|
||||
"""
|
||||
判断当前连接来源是否属于可信代理
|
||||
|
||||
:param remote_addr: 与应用直接建立连接的来源IP
|
||||
:return: 是否信任代理头
|
||||
"""
|
||||
trusted_proxy_ips = cls._get_trusted_proxy_ips()
|
||||
return '*' in trusted_proxy_ips or remote_addr in trusted_proxy_ips
|
||||
|
||||
@classmethod
|
||||
def _get_trusted_proxy_ips(cls) -> set[str]:
|
||||
"""
|
||||
获取可信代理IP集合
|
||||
|
||||
:return: 可信代理IP集合
|
||||
"""
|
||||
return {item.strip() for item in AppConfig.app_trusted_proxy_ips.split(',') if item.strip()}
|
||||
Reference in New Issue
Block a user