Django权限相关方法:
request.user下权限方法:
get_group_permissions(obj=None)
返回用户组权限的集合。
get_all_permissions(obj=None)
返回用户所有的权限集合。
has_perm(perm, obj=None)
用户是否具有某个权限。perm的格式是 "<app label>.<permission codename>".
has_perms(perm_list, obj=None)
用户是否具有权限列表中的每个权限。
自定义Django权限
一、重写User表
、继承AbstractBaseUser和PermissionsMixin
、自定义Meta中的permissions对象
permissions=(
("crm_table_index","可以查看所有的Alexadmin的APP"),
("crm_table_list","可以查看每张表里所有的数据"),
("crm_table_list_view","可以访问表里每条数据的修改页"),
("crm_table_list_change","可以对表里的每条数据进行修改")
)
、执行makemigrations和migrate后,确定在auth_permission表中已经自动写入了2中自定义的permissions
二、定义一个Model用于存放自定义更加权限
、相比auth_permission表,权限颗粒度更细
、可以包含GET,POST等request.method
、可以包含GET访问字段,GET访问字段的值
、可以自定义函数来实现各种自定义权限(数据库中将函数已字符串形式存储)
'crm_table_list':['model_table_list','GET',[],{'source':1},perm_custom_funcs.only_view_own_customers],#可以查看每张表里所有的数据
三、定义一个装饰器,用户Check View视图
def check_permission(func):
"""权限Check装饰器"""
def wrapper(*args, **kwargs):
request = args[0]
if perm_check(*args, **kwargs):
return func(*args, **kwargs)
else:
return render(request, "alexadmin/403.html")
return wrapper
class CheckPermission(View):
"""重写View的dispath方法,让CBV继承该类"""
def dispatch(self, request, *args, **kwargs):
if not perm_check(request, *args, **kwargs):
return render(request, "alexadmin/403.html")
return super(CheckPermission, self).dispatch(request, *args, **kwargs)
四、自定义一个perm_check来对权限进行比较
1、通过request.user.get_all_permissions()方法获取用户所有权限(其实是从auth_permission表中获取)
2、如果权限为空,则直接返回403错误
3、将获取到的权限到自定义permissions数据中进行Filter出来
、从request中获取GET,POST,URL等信息与第3步中Filter出来的详细信息进行对比
、比较通过就放行,不通过就返回403页面
五、 相关代码
admin_permissions
perm_dict = {
"crm_table_index": ["app_index", "GET", [], {}, ], # app_index是URL路由中每条url对应的name
"crm_table_list": ["model_table_list", "GET", [], {"source": 1},],
"crm_table_list_view": ["table_obj_change", "GET", ["source", "consultant"], {}],
"crn_table_list_change": ["table_obj_change", "POST", ["source"], {}]
}
permision_handle
from AlexAdmin import admin_permissions
from django.core.urlresolvers import resolve
from django.views import View
from django.shortcuts import redirect, render
from django.conf import settings
def perm_check(request, *args, **kwargs):
"""
1. 判断用户是否已登录
1.1 根据原生URL获取到相对的URL_name
1.2 根据URL_name循环permission_dict, 找到对应的权限条目
1.2.1 判断request.method 请求参数,是否都匹配
1.2.2 获取最终对应的权限条目
1.2.3 判断用户是否有这条权限
1.2.4 如果有,授权通过
1.2.5 没有权限,返回403错误
1.3 找不到对应权限条目,返回403错误
2. 没有登录,跳转到登录页面
3. 权限相关的方法
get_group_permissions(obj=None)
返回用户组权限的集合。
get_all_permissions(obj=None)
返回用户所有的权限集合。
has_perm(perm, obj=None)
用户是否具有某个权限。perm的格式是 "<app label>.<permission codename>".
has_perms(perm_list, obj=None)
用户是否具有权限列表中的每个权限。
is_anonymous()
是否是匿名用户。
is_authenticated()
用户是否通过验证,登陆。
get_full_name()
返回first_name plus the last_name, with a space in between.
get_short_name()
返回first_name.
set_password(raw_password)
设置密码。
check_password(raw_password)
验证密码。
"""
resolve_url_obj = resolve(request.path)
print("result_url_obj======>", resolve_url_obj) # ResolverMatch(func=AlexAdmin.views.AppIndex, args=(), kwargs={}, url_name=app_index, app_names=[], namespaces=[])
current_url_name = resolve_url_obj.url_name
print("current_url_name======>", current_url_name) # app_index
match_key = None
match_results = [None]
if not request.user.is_authenticated():
return redirect(settings.LOGIN_URL)
print(request.user.username)
print("admin_permissions.perm_dict=====+>>>", admin_permissions.perm_dict )
for permission_key, permission_val in admin_permissions.perm_dict.items():
print("perm_check, permission_val============>", perm_check, permission_val)
# 'crm_table_list': ['model_table_list', 'GET', [], {'source':1},perm_custom_funcs.only_view_own_customers]
perm_url_name = permission_val[0]
perm_method = permission_val[1]
perm_args = permission_val[2]
perm_kwargs = permission_val[3]
custom_func_hook = None if len(permission_val) == 4 else permission_val[4]
if perm_url_name == current_url_name:
print("perm_url_name======>", perm_url_name)
if perm_method == request.method:
args_matched = False
for item in perm_args:
request_method_func = getattr(request, perm_method) # GET or POST
if request_method_func.get(item, None): # 判断request 字典中是否有该参数
args_matched = True
else:
args_matched = False
break # 只要有一个参数不能匹配成功,则判定为假,直接退出循环。
else:
args_matched = True
kwargs_matched = True
for k, v in perm_kwargs.items():
request_method_func = getattr(request, perm_method)
arg_val = request_method_func.get(k, None) # 判断request 字典中是否有该参数
if arg_val == str(v): # 匹配上了特定的参数及对应的参数值,比如request对象里必须有一个user_id=3的参数
kwargs_matched = True
else:
kwargs_matched = False
break # 只要有一个参数不能匹配成功,则判定为假,直接退出循环。
else:
kwargs_matched = True
func_hook_passed = True
if custom_func_hook: # 配置了自定义权限控制函数
func_res = custom_func_hook(*args, **kwargs)
if func_res:
func_hook_passed = True
else:
func_hook_passed = False
match_results = [args_matched, kwargs_matched, func_hook_passed]
print("match_results==========>", match_results)
if all(match_results):
match_key = permission_key
break
if all(match_results):
app_name, *perm_name = match_key.split("_")
perm_obj = "%s.%s" % (app_name, match_key)
if request.user.has_perm(perm_obj):
print("当前用户有此权限")
return True
else:
return False
else:
print("未匹配到权限项, 当前用户无权限")
class CheckPermission(View):
def dispatch(self, request, *args, **kwargs):
if not perm_check(request, *args, **kwargs):
return render(request, "alexadmin/403.html")
return super(CheckPermission, self).dispatch(request, *args, **kwargs)
View视图
class AppIndex(CheckPermission):
def get(self, request):
return render(request, "alexadmin/app_index.html", {"site": site})