自动生成权限或菜单时,接口清单不完整或混入基础接口,常见表现为权限漂移、功能入口误配、运维反复回滚。
本文围绕 swagger 文档拉取与动作接口提取链路拆解,聚焦地址拼装、正则匹配、过滤规则、输出结构。
文章目录
需求解析
材料包含两段能力:从本机启动的 Django 服务拉取 swagger.json 原始文本;从 swagger.json 文本中提取动作接口路径并生成动作数据结构。
| 项目 | 内容 |
|---|---|
| 运行环境 | 本机启动的 Django 服务 |
| 文档入口 | swagger.json |
| 输入参数 | host、port、app_name、component_name |
| 输出目标 | 动作接口清单,包含动作名、接口路径、请求方式映射值 |
动作提取
文档获取
确认服务地址
拉取接口文档
匹配接口路径
识别请求方式
剔除基础接口
组装动作数据
页面支持直接配置端口权限,并配合去重规则,将基础功能与视图动作接口集中完成配置。

功能实现
定位对象 fetch_swagger_text。目的拼出 swagger.json 地址并拉取原始文本,作为解析输入。
python
def fetch_swagger_text(host=None, port=None):
"""
从本机启动的 Django 服务拉取 swagger.json 原始文本
"""
host = host or '127.0.0.1'
port = port or os.environ.get('PORT', '8000')
url = f'http://{host}:{port}/swagger.json'
resp = requests.get(url)
resp.raise_for_status()
return resp.text
需要注意的是 raise_for_status() 属于硬失败策略,服务未启动或路由未暴露会直接抛错中断链路。
定位对象 extract_action_paths。目的从 swagger.json 文本提取动作接口路径与请求方式,剔除基础接口并生成动作数据结构。
python
def extract_action_paths(swagger_text, app_name, component_name):
"""
用正则从 swagger.json 文本中提取所有 /api/{app}/{comp}/<action> 接口
并剔除基础的 CRUD、import_data、export_data
返回格式为 [('/api/.../path/', 'get'), ...]
"""
prefix = re.escape(f'/api/{app_name}/{component_name}/')
# 匹配路径及请求方法,示例:"paths":{"/api/.../foo/":{"get":{...},...}, ...}
pattern = rf'"({prefix}[^"]+?)"\s*:\s*\{{\s*"(get|post|put|patch|delete)"'
matches = re.findall(pattern, swagger_text, flags=re.IGNORECASE)
seen = set()
actions = []
base_suffixes = {'', '{id}/', 'import_data/', 'export_data/'}
for full_path, method in matches:
# 只截 actionName/ 或 actionName/{id}/
suffix = full_path.replace(f'/api/{app_name}/{component_name}/', '')
# 剔除基础接口
if any(suffix.startswith(bs) for bs in base_suffixes):
continue
key = (full_path, method.lower())
if key not in seen:
seen.add(key)
action = suffix.rstrip('/').split('/')[0]
actions.append({
'menu': None, # 后续在调用处填入 menu_obj.id
'name': action,
'value': f'{app_name.replace("/", ":")}:{component_name}:{action.capitalize()}',
'api': full_path + '/', # 保持末尾 /
'method': {'get': 0, 'post': 1, 'put': 2, 'patch': 2, 'delete': 3}[method.lower()]
})
return actions
用于明确提取动作接口时的入参边界,三者共同决定匹配前缀与解析范围,任意一项不准确都会导致匹配为空或误匹配到其他模块接口。
| 参数 | 含义 | 约束 |
|---|---|---|
| swagger_text | swagger.json 原始文本 | 必须为完整文本 |
| app_name | 应用名 | 用于拼接接口前缀 |
| component_name | 组件名 | 用于拼接接口前缀 |
用于锁定需要剔除的基础接口类型,目标是只保留视图动作类接口,避免 CRUD、导入导出等通用端点混入动作清单,引发权限配置膨胀或入口误挂载。
| 过滤项 | 说明 |
|---|---|
| 资源集合基础接口 | 组件根路径对应的基础资源入口 |
| 单条资源基础接口 | 带记录标识的基础资源入口 |
| 导入接口 | import_data 对应的数据导入入口 |
| 导出接口 | export_data 对应的数据导出入口 |
用于定义请求方式到权限系统内部枚举值的映射规则,映射保持稳定才能保证同一接口在不同环境生成出的权限记录一致,否则会出现同路径不同 method 值导致的重复或覆盖。
| 请求方式 | method 映射值 |
|---|---|
| get | 0 |
| post | 1 |
| put | 2 |
| patch | 2 |
| delete | 3 |
用于描述最终动作数据结构的字段口径,menu 负责绑定页面入口,name 与 value 承担动作标识与展示编码,api 与 method 决定权限命中条件,需要注意的是 api 末尾斜杠统一处理用于减少路径差异带来的匹配失败。
| 输出字段 | 含义 | 关键约束 |
|---|---|---|
| menu | 菜单标识 | 初始为 None,调用侧补齐 |
| name | 动作名 | 取路径后缀的首段 |
| value | 动作编码 | app_name 会做分隔符替换 |
| api | 接口路径 | 末尾补 / |
| method | 请求方式映射 | 由请求方式映射表生成 |
这一步不能省略去重逻辑,否则会导致同一路径与同一请求方式在不同匹配场景下重复入库或重复展示。
总结
该实现将接口文档获取与动作接口提取拆为两段,前段只负责稳定获取 swagger 原文,后段集中处理匹配、过滤与结构化输出,边界清晰。
风险集中在正则匹配与路径规范,文档结构变化、路径末尾斜杠差异、基础接口后缀新增,都会导致动作清单偏差,过滤集合需要随接口约定同步维护。
该链路可复用在权限生成、菜单注册、接口盘点场景,价值体现在清单稳定性、维护成本可控、权限口径一致性更容易落地。