Django如何通过URL配置为不同路由分配用户访问权限
解决Django URL层批量权限控制的方案
嘿,这个需求太常见了——当有大量URL要分组控制权限,又不想动每个视图函数的时候,完全可以在URL配置层搞定,不用碰业务视图代码!下面给你两种实用的方案,适配你80多个URL的场景:
核心思路
利用Django自带的user_passes_test装饰器,把权限校验逻辑直接包装到URL对应的视图入口上,这样请求匹配到URL时会先做权限校验,通过了才会进入视图处理。
方案1:逐个URL包装(适合少量特殊URL)
如果只有个别URL(比如你的路由A)需要单独控制,其余大部分URL统一用另一组权限,那可以直接在URL里给对应的视图套装饰器:
首先定义两个组校验函数:
from django.contrib.auth.decorators import user_passes_test # 校验用户是否在group_a(允许访问路由A的组) def is_in_group_a(user): # 这里可以用组名或者组ID,用ID更避免重名风险 return user.groups.filter(name="group_a").exists() # 校验用户是否在group_b(允许访问B/C/D等路由的组) def is_in_group_b(user): return user.groups.filter(name="group_b").exists()
然后修改你的URL配置:
urlpatterns = [ # 路由A:仅允许group_a访问 url(r'^A/$', user_passes_test(is_in_group_a)(django.contrib.auth.views.login)), # 路由B/C/D及其他URL:允许group_b访问 url(r'^B/$', user_passes_test(is_in_group_b)(logout_page)), url(r'^C/$', user_passes_test(is_in_group_b)(c_method)), url(r'^D/$', user_passes_test(is_in_group_b)(D_method)), # 剩下的70多个URL都按照这个格式套装饰器就行 ]
方案2:批量包装URL(适合大量URL)
如果有80多个URL要统一用group_b的权限,一个个套装饰器太麻烦,咱们可以写个小工具函数批量处理:
from django.conf.urls import url from django.contrib.auth.decorators import user_passes_test # 先定义权限校验函数(和方案1一样) def is_in_group_a(user): return user.groups.filter(name="group_a").exists() def is_in_group_b(user): return user.groups.filter(name="group_b").exists() # 批量包装视图的工具函数 def wrap_urls_with_permission(url_list, permission_func): wrapped_urls = [] for url_obj in url_list: # 取出原URL的视图,用权限装饰器包装后重建URL对象 wrapped_view = permission_func(url_obj.callback) wrapped_urls.append( url(url_obj.regex.pattern, wrapped_view, name=url_obj.name) ) return wrapped_urls # 第一步:把所有需要group_b权限的URL单独列出来 group_b_urls = [ url(r'^B/$', logout_page), url(r'^C/$', c_method), url(r'^D/$', D_method), # 剩下的70多个URL都放到这里 ] # 第二步:组合最终的urlpatterns urlpatterns = [ # 单独处理路由A url(r'^A/$', user_passes_test(is_in_group_a)(django.contrib.auth.views.login)), ] + wrap_urls_with_permission(group_b_urls, user_passes_test(is_in_group_b))
这样只需要维护一个group_b_urls列表,批量一次包装,代码更简洁,也不容易漏改。
额外优化:自定义无权限响应
默认情况下,用户没有权限会跳转到登录页,如果想返回403禁止访问或者自定义页面,可以给user_passes_test加参数:
# 跳转到自定义登录页 user_passes_test(is_in_group_a, login_url='/custom-login/') # 直接返回403错误 from django.http import HttpResponseForbidden def is_in_group_a(user): if user.groups.filter(name="group_a").exists(): return True return HttpResponseForbidden("抱歉,你没有访问该页面的权限")
内容的提问来源于stack exchange,提问作者niran
相关产品推荐
相关产品推荐

