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})