
本文介绍如何安全、灵活地解析并执行用户通过 JSON 等外部配置文件提供的动态条件表达式(如 (Bob.age == Jane.age) || (Bob.age
本文介绍如何安全、灵活地解析并执行用户通过 json 等外部配置文件提供的动态条件表达式(如 `(bob.age == jane.age) || (bob.age
在构建报表系统、规则引擎或低代码平台时,常需支持用户自定义逻辑判断——例如根据人员属性(Bob.age, Jane.age)编写类似 (Bob.age == Jane.age) || (Bob.age 的布尔表达式,并在运行时动态求值。虽然 Python 的 eval() 函数看似“开箱即用”,但直接执行任意字符串存在严重安全隐患(如执行 __import__('os').system('rm -rf /')),绝不可用于生产环境中的用户输入。
✅ 推荐方案:使用专为安全表达式求值设计的轻量库 —— simpleeval(推荐首选)
它默认禁用函数调用、导入、赋值等危险操作,仅支持安全的算术、比较、逻辑运算及括号嵌套,且允许白名单式注入变量:
from simpleeval import SimpleEval
# 已知数据表(name → object with attributes)
data = {
"Bob": type('Person', (), {'age': 47})(),
"Bill": type('Person', (), {'age': 44})(),
"Jane": type('Person', (), {'age': 36})(),
"Steve": type('Person', (), {'age': 22})(),
}
# 用户提供的条件表达式(来自 JSON 文件)
user_expr = "(Bob.age == Jane.age) or (Bob.age <p>⚠️ 注意事项: </p>
- JSON 不支持
||/&&,必须转换为 Python 风格的or/and(可在解析 JSON 后用.replace('||', 'or').replace('&&', 'and')预处理); -
simpleeval默认不支持点号访问(如Bob.age),需启用attrgetter支持:from simpleeval import SimpleEval, Attribute s = SimpleEval() s.functions['getattr'] = getattr s.names = data # 或更简洁:使用 patched 版本(v0.9.13+ 内置支持 . 属性访问)
? 进阶需求(如自定义函数、类型转换)可选用 pyparsing 构建领域专用解析器,或采用 lark 实现完整语法树控制;若需模板化输出(如生成 JSON 结构),Jinja2 是优秀选择,但其核心定位是模板渲染,而非纯条件求值——上文答案中混用 {% if ... %}true{% else %}false{% endif %} 并非最佳实践,易引入模板逻辑复杂度与 XSS 风险。
? 总结:
- ❌ 拒绝
eval()/exec()处理用户输入; - ✅ 优先选用
simpleeval,配置names上下文 + 启用属性访问,兼顾安全性与简洁性; - ? 对复杂规则(如时间函数、正则匹配),可扩展
simpleeval.functions白名单(如{'today': datetime.date.today}); - ? 始终对用户表达式做语法预检(
s.eval("1+1")测试是否抛出InvalidExpression)。
通过合理选型与严格上下文管控,你能在保障系统安全的前提下,高效赋能用户驱动的动态条件逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











