Python中Flask利用url_map进行简单权限管理的实现思路
最近在弄 flask 简单的权限管理,想到一种实现方式:
利用 url_map 把所有的连接路径导出
Map([<Rule '/topics/create' (GET, OPTIONS, HEAD, POST) -> topics.cre
<Rule '/topics/latest' (GET, OPTIONS, HEAD) -> topics.latest>,
<Rule '/users/setting' (GET, OPTIONS, HEAD, POST) -> users.setting>
<Rule '/auth/signout' (GET, OPTIONS, HEAD) -> auth.signout>,
<Rule '/auth/signin' (GET, OPTIONS, HEAD, POST) -> auth.signin>,
<Rule '/auth/signup' (GET, OPTIONS, HEAD, POST) -> auth.signup>,
<Rule '/auth/reset' (GET, OPTIONS, HEAD, POST) -> auth.reset>,
<Rule '/auth/find' (GET, OPTIONS, HEAD, POST) -> auth.find>,
<Rule '/topics/' (GET, OPTIONS, HEAD) -> topics.index>,
<Rule '/' (GET, OPTIONS, HEAD) -> frontend.index>,
<Rule '/topics/<id>/reply' (OPTIONS, POST) -> topics.reply>,
<Rule '/topics/<id>' (GET, OPTIONS, HEAD) -> topics.topic>,
<Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>,
<Rule '/users/<username>' (GET, OPTIONS, HEAD) -> users.index>])
然后在 flask 里面添加权限控制页面将每个路径授权给用户。 具体方式为:数据库用户表增加一列,把允许的内容存为字典或者 json 串。每次请求时候比对路径是否在字典里面如果在就允许访问。 扩展开来,类似传参和 get、post 不同的访问也可以很方便的判断。 具体 url_map 使用参考这里: https://segmentfault.com/q/1010000000698148
但是现在有个问题是当启用了 blueprint 后,url_map 居然无法直接显示,大家有啥办法没?
Python中Flask利用url_map进行简单权限管理的实现思路
在Flask里用url_map做权限管理,核心思路就是利用app.url_map这个属性来获取所有已注册的路由规则,然后根据当前用户权限来过滤。下面是一个可以直接跑的示例:
from flask import Flask, request, abort, render_template_string
from functools import wraps
app = Flask(__name__)
# 模拟用户权限数据
USER_PERMISSIONS = {
'user1': ['/admin', '/dashboard'],
'user2': ['/dashboard', '/profile']
}
def permission_required(allowed_paths):
"""装饰器:检查用户是否有权限访问特定路径"""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# 获取当前用户(这里简单用查询参数模拟)
current_user = request.args.get('user', 'guest')
# 获取当前请求的路径
current_path = request.path
# 检查路径是否在允许列表中
if current_user in USER_PERMISSIONS:
allowed = USER_PERMISSIONS[current_user]
# 检查精确匹配或前缀匹配
if any(current_path.startswith(path) for path in allowed):
return f(*args, **kwargs)
abort(403) # 没有权限
return decorated_function
return decorator
# 动态注册路由时应用权限控制
def register_protected_route(rule, endpoint, view_func, allowed_paths, **options):
"""注册带权限控制的路由"""
wrapped_func = permission_required(allowed_paths)(view_func)
app.add_url_rule(rule, endpoint, wrapped_func, **options)
# 视图函数
def admin_page():
return "Admin Area"
def dashboard():
return "Dashboard"
def profile():
return "User Profile"
# 手动注册路由并指定权限路径
register_protected_route('/admin', 'admin', admin_page, ['/admin'])
register_protected_route('/dashboard', 'dashboard', dashboard, ['/dashboard'])
register_protected_route('/profile', 'profile', profile, ['/profile'])
# 公开路由
@app.route('/')
def index():
return render_template_string('''
<h1>测试链接:</h1>
<a href="/admin?user=user1">user1访问/admin</a><br>
<a href="/admin?user=user2">user2访问/admin</a><br>
<a href="/dashboard?user=user1">user1访问/dashboard</a>
''')
if __name__ == '__main__':
app.run(debug=True)
这个实现的关键点:
-
app.url_map的使用:虽然示例中直接用了request.path,但在更复杂的场景下,你可以遍历app.url_map.iter_rules()来获取所有注册的路由,然后建立权限映射表。 -
装饰器模式:通过装饰器在请求进入视图函数前进行权限校验,保持代码干净。
-
路径匹配:使用
startswith()进行前缀匹配,这样/admin可以匹配/admin、/admin/users等子路径。 -
动态路由注册:通过
register_protected_route函数封装路由注册逻辑,确保权限控制与路由绑定。
更高级的实现可以考虑:
- 把权限数据存数据库
- 支持正则表达式匹配
- 集成到Flask的
before_request钩子做全局控制 - 用蓝图(Blueprint)来分组管理权限
不过对于简单需求,上面这个方案完全够用了。
总结:用url_map做权限控制就是路由和权限的映射管理。
url_map 倒不是关键问题,看一下源码或者搜索一下应该就能解决。主要是需要这么细粒度的权限管理吗,还要查数据库,而且耦合还很严重,加页面得更新数据库

