Web系统中高效提取请求信息是提升开发效率与安全审计的重要手段。通过封装常用请求处理逻辑,可避免重复造轮子,标准化请求数据的收集与分析过程,支撑上层日志、监控与风控系统的建设。
本文围绕 request_util.py
源码,解析如何在 Django+DRF 项目中提取用户、IP、请求参数、设备信息,并结合外部接口实现地理位置分析。通过工具化封装,统一了数据提取逻辑,提升了项目整体的可维护性与拓展性。
文章目录
request_util.py
系统基于 Django 和 DRF 框架开发,dvadmin/utils/request_util.py
作为请求工具模块,封装了对 Request 请求对象的常用操作。通过标准化提取请求用户、IP地址、参数、路径、浏览器信息、系统信息等数据,提升开发效率和代码复用性,同时支撑后台登录日志记录、行为审计等功能模块。
项目特点 | 描述 |
---|---|
技术栈 | Django + DRF |
功能定位 | 统一处理请求数据提取、用户认证、IP分析、日志保存 |
辅助功能 | 提供 IP 地理位置分析与请求设备信息提取 |
设计模式 | 工具类封装,便于全局调用 |
dvadmin/utils/request_util.py
提供一系列针对 HTTP Request 对象的辅助函数,包括提取当前请求用户、IP 地址、请求参数、标准化路径、解析浏览器和操作系统信息。同时还内置了与外部接口对接的 IP 地址分析功能,用于获取详细的地理位置数据,并提供 save_login_log
方法自动记录登录日志。这些工具函数统一了系统内部对于请求数据的处理方式,降低了开发成本和维护难度。
模块职责 | 说明 |
---|---|
用户获取 | 自动认证并返回请求关联的用户对象 |
请求IP提取 | 从请求头中智能提取真实客户端IP地址 |
请求参数提取 | 合并GET、POST、Body数据为统一格式 |
路径标准化处理 | 支持动态ID占位标准化请求路径,便于日志和权限管理 |
浏览器与系统识别 | 通过 User-Agent 分析浏览器和操作系统信息 |
IP地理位置分析 | 基于外部API接口解析IP地址详细地理信息 |
登录日志保存 | 自动记录用户登录时的环境数据和地理信息 |
在用户认证、行为日志、审计日志、异常分析等场景中,需要频繁提取用户信息、IP 地址、请求参数。通过使用 dvadmin/utils/request_util.py
中封装的方法,可以标准化这些操作,并且降低代码重复。适用于统一收集请求元数据、记录安全日志、分析访问来源等应用场景,确保后台数据链完整可靠。
使用场景 | 说明 |
---|---|
后台统一提取登录用户 | 支持未认证时手动认证 JWT Token,避免异常 |
API 请求日志审计 | 提取访问路径、参数、IP,用于日志记录与审计分析 |
登录地理位置统计与风控 | 分析IP归属地,辅助判断异常登录行为 |
异常行为追踪 | 通过浏览器、系统、IP信息综合识别异常访问模式 |
统一保存用户登录日志 | 自动记录详细设备信息和地理数据,便于后台管理与统计分析 |
项目源码解析
获取请求用户对象
用于从 request 中提取用户对象,如果 request.user 未认证,则尝试手动通过 JWT 认证机制进行认证,最终保证返回一个用户对象或匿名用户对象。依赖 DRF SimpleJWT 的认证模块,适配有登录状态检查的接口场景。
def get_request_user(request):
user: AbstractBaseUser = getattr(request, 'user', None)
if user and user.is_authenticated:
return user
try:
user, token = JWTAuthentication().authenticate(request)
except Exception:
pass
return user or AnonymousUser()
获取请求来源 IP 地址
提取请求头中的 HTTP_X_FORWARDED_FOR
或 REMOTE_ADDR
信息作为客户端 IP 地址,适配常见反向代理部署场景。该方法对于登录日志、IP 限制、安全防护模块非常关键。
def get_request_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[-1].strip()
return ip
ip = request.META.get('REMOTE_ADDR', '') or getattr(request, 'request_ip', None)
return ip or 'unknown'
获取请求参数数据
统一提取 GET、POST、Body 传递的参数,支持 JSON 格式解析,保证接口内部无论何种方式传参都可以标准化获取数据,提升接口兼容性。
def get_request_data(request):
request_data = getattr(request, 'request_data', None)
if request_data:
return request_data
data: dict = {**request.GET.dict(), **request.POST.dict()}
if not data:
try:
body = request.body
if body:
data = json.loads(body)
except Exception:
pass
if not isinstance(data, dict):
data = {'data': data}
return data
动态生成统一请求路径
将请求路径中的具体参数(如 ID)替换成 {id}
通配符,规范化日志或权限规则中记录的接口路径格式,保证路径识别的一致性。
def get_request_path(request, *args, **kwargs):
request_path = getattr(request, 'request_path', None)
if request_path:
return request_path
values = []
for arg in args:
if isinstance(arg, str):
values.append(arg)
elif isinstance(arg, (tuple, set, list, dict)):
values.extend(arg if not isinstance(arg, dict) else arg.values())
if not values:
return request.path
path: str = request.path
for value in values:
path = path.replace('/' + value, '/{id}')
return path
规范化请求路径
利用 Django ResolverMatch
对象,根据路径参数动态替换生成统一规范格式,适用于更复杂的动态路径匹配,如批量对象访问接口的标准化处理。
def get_request_canonical_path(request):
request_path = getattr(request, 'request_canonical_path', None)
if request_path:
return request_path
path: str = request.path
resolver_match: ResolverMatch = request.resolver_match
for value in resolver_match.args:
path = path.replace(f"/{value}", "/{id}")
for key, value in resolver_match.kwargs.items():
if key == 'pk':
path = path.replace(f"/{value}", "/{id}")
else:
path = path.replace(f"/{value}", f"/{{{key}}}")
return path
获取浏览器信息
解析 User-Agent
请求头信息,提取访问设备所使用的浏览器类型,用于登录日志、访问分析、设备识别等场景。
def get_browser(request):
ua_string = request.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
return user_agent.get_browser()
获取操作系统信息
通过解析 User-Agent
字符串,提取客户端设备的操作系统信息,辅助进行平台适配、异常分析或访问统计。
def get_os(request):
ua_string = request.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
return user_agent.get_os()
获取模型描述信息
根据 QuerySet、视图或模型实例动态提取 Django 模型的 verbose_name
属性,用于日志、审计、权限等系统内部描述展示。
def get_verbose_name(queryset=None, view=None, model=None):
try:
if queryset is not None and hasattr(queryset, 'model'):
model = queryset.model
elif view and hasattr(view.get_queryset(), 'model'):
model = view.get_queryset().model
elif view and hasattr(view.get_serializer(), 'Meta') and hasattr(view.get_serializer().Meta, 'model'):
model = view.get_serializer().Meta.model
if model:
return getattr(model, '_meta').verbose_name
except Exception:
pass
return model if model else ""
获取 IP 地址地理信息
调用外部 IP 解析服务接口,根据 IP 地址返回详细地理位置信息,包括国家、省份、城市、运营商等数据,增强登录安全与统计分析能力。
def get_ip_analysis(ip):
data = {
"continent": "", "country": "", "province": "", "city": "", "district": "",
"isp": "", "area_code": "", "country_english": "", "country_code": "",
"longitude": "", "latitude": ""
}
if ip != 'unknown' and ip:
if getattr(settings, 'ENABLE_LOGIN_ANALYSIS_LOG', True):
try:
res = requests.get(url='https://ip.django-vue-admin.com/ip/analysis', params={"ip": ip}, timeout=5)
if res.status_code == 200:
res_data = res.json()
if res_data.get('code') == 0:
data = res_data.get('data')
return data
except Exception as e:
print(e)
return data
保存登录日志记录
收集用户登录时的各种信息,如 IP、设备、地理位置,并将其写入系统登录日志表 LoginLog
,用于系统审计、行为分析和异常检测。
def save_login_log(request):
ip = get_request_ip(request=request)
analysis_data = get_ip_analysis(ip)
analysis_data['username'] = request.user.username
analysis_data['ip'] = ip
analysis_data['agent'] = str(parse(request.META['HTTP_USER_AGENT']))
analysis_data['browser'] = get_browser(request)
analysis_data['os'] = get_os(request)
analysis_data['creator_id'] = request.user.id
analysis_data['dept_belong_id'] = getattr(request.user, 'dept_id', '')
LoginLog.objects.create(**analysis_data)
应用案例
请求信息提取与日志记录机制在后台管理系统中的应用
在后台管理系统中,高效、标准化地提取用户、IP、请求参数、设备信息等请求数据是提升安全性和开发效率的关键。通过 dvadmin/utils/request_util.py
模块,系统实现了对 HTTP 请求的全面封装与提取,确保在各类场景下能够统一获取请求相关信息。该模块不仅支持用户认证、请求参数提取、IP 地址分析,还通过调用外部接口分析 IP 地理位置,为登录日志和安全审计提供基础数据。
功能点 | 内容描述 |
---|---|
场景需求 | 高效、标准化地提取 HTTP 请求相关信息(如用户、IP、请求参数、设备信息等),提升系统安全性与开发效率,支持安全审计与风控分析。 |
核心模块 | dvadmin/utils/request_util.py :封装 HTTP 请求相关信息提取功能,统一获取请求数据,便于日志记录与安全分析。 |
支持功能 | - 用户认证提取:解析请求中的用户认证信息,包括用户身份与角色。 |
- 请求参数提取:支持 GET 和 POST 参数的统一解析与提取,便于后续业务处理。 | |
- IP 地址分析:提取客户端 IP 地址,并支持调用外部服务进行 IP 地理位置分析。 | |
- 设备信息获取:解析客户端 User-Agent 信息,识别操作系统、浏览器等设备信息。 | |
实现机制 | - 封装 Django 请求对象:通过对 Django HttpRequest 对象的扩展,统一访问请求数据。 |
- 外部接口调用:通过集成第三方 API 服务(如 IP 地理位置查询),提升 IP 地址分析能力。 |
在实际开发中,管理员登录、操作行为、IP 源分析等关键信息都通过该模块统一提取并保存到日志系统,为后续的风控和异常行为分析提供重要依据。以下是基于该模块实现的具体业务功能与操作。
功能点 | 内容描述 |
---|---|
应用场景 | - 用户登录日志:记录用户登录时的 IP 地址、设备信息,用于安全审计与异常行为分析。 |
- 操作行为审计:提取管理员操作请求中的详细信息,存入日志系统,追踪操作来源与行为。 | |
- 风控分析:结合 IP 地址地理位置数据,识别异常登录或操作行为。 | |
优势 | - 提供统一的数据提取接口,减少重复开发工作。 - 支持外部服务集成,增强数据分析能力。 - 提升系统安全性与可观测性。 |
扩展能力 | - 支持更多设备信息字段的解析(如分辨率、网络类型)。 - 集成更加丰富的外部分析服务,如风险评分与威胁情报数据。 |
请求数据提取与日志记录操作示例
在每次用户登录时,系统需要记录用户信息、设备信息以及登录来源的地理位置。通过调用 save_login_log
函数,自动提取当前请求的用户信息、设备类型、操作系统、IP 地址及其地理位置信息,并存储到系统的登录日志表中。代码示例如下:
def save_login_log(request):
ip = get_request_ip(request=request)
analysis_data = get_ip_analysis(ip)
analysis_data['username'] = request.user.username
analysis_data['ip'] = ip
analysis_data['agent'] = str(parse(request.META['HTTP_USER_AGENT']))
analysis_data['browser'] = get_browser(request)
analysis_data['os'] = get_os(request)
analysis_data['creator_id'] = request.user.id
analysis_data['dept_belong_id'] = getattr(request.user, 'dept_id', '')
LoginLog.objects.create(**analysis_data)
此函数将用户登录时的详细信息存入 LoginLog
表,为后续的审计和风控提供数据支持。
动态获取请求参数与标准化路径
在 API 请求中,获取请求的参数和路径是常见需求。通过 get_request_data
和 get_request_path
函数,能够动态提取请求参数并规范化路径,简化日志记录和权限管理的复杂度。例如,在某个接口中,前端传递了 user_id
,系统自动将其替换为 {id}
,实现路径的标准化,确保一致的日志记录格式。
def get_request_path(request, *args, **kwargs):
request_path = getattr(request, 'request_path', None)
if request_path:
return request_path
values = []
for arg in args:
if isinstance(arg, str):
values.append(arg)
elif isinstance(arg, (tuple, set, list, dict)):
values.extend(arg if not isinstance(arg, dict) else arg.values())
if not values:
return request.path
path: str = request.path
for value in values:
path = path.replace('/' + value, '/{id}')
return path
这使得在日志记录时,无论路径中含有何种具体参数,最终记录的日志路径都统一为 {id}
格式,提升了日志的一致性与可追溯性。
请求来源 IP 地址与地理信息分析
IP 地址分析功能可以帮助系统识别用户的登录地理位置,通过 get_ip_analysis
函数调用外部 API 服务获取详细的地理位置数据。在处理登录日志时,可以自动补充如国家、省份、城市等信息,提升日志的业务可读性,帮助风控系统识别潜在风险。
def get_ip_analysis(ip):
data = {
"continent": "", "country": "", "province": "", "city": "", "district": "",
"isp": "", "area_code": "", "country_english": "", "country_code": "",
"longitude": "", "latitude": ""
}
if ip != 'unknown' and ip:
try:
res = requests.get(url='https://ip.django-vue-admin.com/ip/analysis', params={"ip": ip}, timeout=5)
if res.status_code == 200:
res_data = res.json()
if res_data.get('code') == 0:
data = res_data.get('data')
except Exception as e:
print(e)
return data
用户与设备信息解析
通过 get_browser
和 get_os
函数提取请求头中的 User-Agent
信息,识别用户访问设备的浏览器类型和操作系统信息,便于后期日志分析和异常行为识别:
def get_browser(request):
ua_string = request.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
return user_agent.get_browser()
def get_os(request):
ua_string = request.META['HTTP_USER_AGENT']
user_agent = parse(ua_string)
return user_agent.get_os()
这使得在进行安全审计时,能够综合浏览器、操作系统、IP 地址等多维度信息识别用户的访问行为,帮助系统发现潜在的异常访问模式。
通过 dvadmin/utils/request_util.py
模块的封装,系统实现了高效、标准化的请求数据提取和日志记录,提升了开发效率和安全性。在后台管理平台中,能够快速集成这些功能,提供灵活的接口日志、监控、风控功能,并为后续的系统扩展和维护提供了便利。
总结
模块以独立工具函数方式封装,覆盖用户识别、IP提取、参数解析、路径标准化等核心功能,减少业务系统中的冗余代码。结合外部API完成IP地理信息补充,提升日志的业务可读性。统一的请求处理逻辑,方便在认证、日志、审计等多个场景中直接调用。
IP地址分析功能依赖外部接口,存在可用性风险且异常处理较弱。请求参数提取逻辑在复杂场景下兼容性不足,异常捕获范围过大。浏览器与系统识别基于 User-Agent 解析库,存在识别准确率波动问题。整体模块缺少缓存与限频机制,存在一定性能优化空间。