zoukankan      html  css  js  c++  java
  • 通用权限系统

    前言:

    权限是什么?

    对于web程序来说,一条权限 = 一个动作 =一个url + 一种请求方法(get/post/put...) + 若干个请求参数(?name="name"&sex=1&age=10 ...)

    用户访问的每个不同的 fullpath就决定了用户能获取到什么;通过区分fullpath就可以做到web程序的权限控制;

    一、Django的auth_permission表

    Django程序在migrate数据库之后,会自动生成一张auth_permission表,这张表专门用户存储用户权限信息;

    那么如何在这张表里新增权限记录呢?

    在model.py的任何一张表下增加class Meta:

    class Customer(models.Model):
        '''
        客户信息表
         '''
        date=models.DateTimeField(auto_now_add=True,verbose_name='合作时间')
        name = models.CharField(max_length=266, verbose_name='客户姓名')
        customer_detail=models.ForeignKey('CustomerDetail',verbose_name='客户详细信息')
        def __str__(self):
            return self.name
    
        class Meta:  # 用户和用户所有的权限,通过Django admin的user表关联起来!
            permissions = (
                       #权限名称                 #权限描述!
                ('view_customer_list', '可以查看客户列表1111'),
                ('view_customer_info', '可查看用客户详细信息11111'),
                ('edit_own_customer_info', '可以删除客户信息111111'),)
    扩展auth_permission表

    二、Django admin 让权限关联上用户

    1.auth_permission表和admin自带的auth_group、user表是M2M关系,

    2.所以就可以通过Django admin直接给 用户/用户组 添加权限了;

     2.给用户关联权限成功之后,user对象的has_perm()就可以去检测该用户 否拥有某个权限?

    import os
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "permission_system.settings")
    import django
    django.setup()
    
    from app01 import models
    
    
    user_obj=models.UserInfo.objects.all()[1]
    print(user_obj) #注意superuser 拥有任何权限,必须是普通用户调用 has_perm()
    print(user_obj.has_perm('app01.view_customer_list')) #True
    user.has_perm(“app名.权限名”)

    三、数据结构设计,让用户权限名 关联上Django的每个url;

    通过以上步骤   

    每个用户仅仅是和权限名称关联了起来,但是真正的权限是url啊!但url又不是固定的;

    所以得 自己设计数据结构 让 用户权限名 关联上url别名;(url别名具有固定标识作用)

    perm_dic = {
        # auth_permissions表权限    url的别名    请求方法  携带参数?name='2GO' 
        'view_customer_list': ['customer_list','GET',[]],
        'view_customer_info': ['customer_detail','GET',[]],
        'edit_own_customer_info': ['customer_detail','POST',['qq','nam']],
    }

    四、通过给视图函数增加装饰器验证用户是否  拥有访问权限?

    让 每个url、url请求方式、?=携带参数,(完整URL) 和用户权限关联之后,就可以在用户访问Django程序的时候,

    抓取到 request.path_info、request.method、request.GET/POST.get(‘args’) 和自己设计好的 数据结构去math了;

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    # Author:Alex Li
    from django.core.urlresolvers import resolve
    from django.shortcuts import render
    perm_dic = {
        'view_customer_list': ['customer_list','GET',[]],
        'view_customer_info': ['customer_detail','GET',[]],
        'edit_own_customer_info': ['customer_detail','POST',['qq','nam']],
    }
    
    def perm_check(*args,**kwargs):
        request = args[0]
        url_resovle_obj = resolve(request.path_info)
        current_url_namespace = url_resovle_obj.url_name
        #app_name = url_resovle_obj.app_name #use this name later
        print("url namespace:",current_url_namespace)
        matched_flag = False # find matched perm item
        matched_perm_key = None
        if current_url_namespace is not None:#if didn't set the url namespace, permission doesn't work
            print("find perm...")
            for perm_key in perm_dic:
                perm_val = perm_dic[perm_key]
                if len(perm_val) == 3:#otherwise invalid perm data format
                    url_namespace,request_method,request_args = perm_val
                    print(url_namespace,current_url_namespace)
                    if url_namespace == current_url_namespace: #matched the url
                        if request.method == request_method:#matched request method
                            if not request_args:#if empty , pass
                                matched_flag = True
                                matched_perm_key = perm_key
                                print('mtched...')
                                break #no need looking for  other perms
                            else:
                                for request_arg in request_args: #might has many args
                                    request_method_func = getattr(request,request_method) #get or post mostly
                                    #print("----->>>",request_method_func.get(request_arg))
                                    if request_method_func.get(request_arg) is not None:
                                        matched_flag = True # the arg in set in perm item must be provided in request data
                                    else:
                                        matched_flag = False
                                        print("request arg [%s] not matched" % request_arg)
                                        break #no need go further
                                if matched_flag == True: # means passed permission check ,no need check others
                                    print("--passed permission check--")
                                    matched_perm_key = perm_key
                                    break
    
        else:#permission doesn't work
            return True
    
        if matched_flag == True:
            #pass permission check
            perm_str = "app01.%s" %(matched_perm_key) #crm.view_customer_list
            if request.user.has_perm(perm_str):
                print("33[42;1m--------passed permission check----33[0m")
                return True
            else:
                print("33[41;1m ----- no permission ----33[0m")
                print(request.user,perm_str)
                return False
        else:
            print("33[41;1m ----- no matched permission  ----33[0m")
    
    
    def check_permission(func):
        def wrapper(*args,**kwargs):
            print('---start check perm---')
            if perm_check(*args,**kwargs) is not True:#no permisssion
                return render(args[0],'403.html')
            return func(*args,**kwargs)
        return  wrapper
    permisssion.py

    五、权限插件和视图的无缝对接

    权限插件完成之后,如何在不修改代码的前提下,通用得 结合到每个项目中呢?使用装饰器;

    from django.shortcuts import render,HttpResponse,redirect
    from app01 import models
    from app01.permission import check_permission
    from django.contrib.auth import authenticate,login,logout
    from django.contrib.auth.decorators import login_required
    from django.views.decorators.csrf import csrf_exempt
    
    
    def acc_login(request):
        error = ''
        if request.method == "POST":
            username = request.POST.get('username')
            password = request.POST.get('password')
            user = authenticate(username=username,password=password)
            if user:
                login(request, user)
                return  redirect('/index/')
            else:
                error = "Wrong username or password!"
        return render(request,'login.html',{'error':error })
    
    @login_required
    def index(request):
        return render(request,'index.html')
    
    
    @login_required
    @check_permission
    def customer_list(request):
        return render(request,'customer_list.html')
    
    @login_required
    @check_permission
    def customer_detail(request):
        return render(request,'customer_detail.html')
    views.py

    六、权限极致到按钮

    如果权限精细到1个URL我感觉还是不够,还可以精细到 1个URL返回的标签;

        def process_response(self, request, response):
            if request.path_info =='/arya/cmdb/worker_order/':
                BS=BeautifulSoup(response.content,"html5lib")
                tags=BS.find_all(class_='btn')
                for tag in tags:
                    tag.decompose()
                response.content=str(BS)
            return response
    中间件+BeautifulSoup过滤
       def process_response(self, request, response):
            #返回相关子工单、父工单返回逻辑
            if request.path_info == '/arya/cmdb/worker_order/':
                current_list_url = '/arya/cmdb/worker_order/'
                curent_page=request.GET.get('page','1')
                request.session['curent_page']=curent_page
    
            if request.path_info == '/arya/cmdb/worker_order/see/':
                current_see_url = '/arya/cmdb/worker_order/see/'
                BS = BeautifulSoup(response.content,"html5lib")
                current_obj=models.Worker_order.objects.get(pk=request.GET.get('id'))
                if current_obj.parent:#子工单
                    go_back_url=current_see_url+'?id='+str(current_obj.parent.pk)
                else:#就是父工单
                    page_number=request.session['curent_page']
                    go_back_url ='/arya/cmdb/worker_order/?page=' + str(page_number)
    
                BS.find(id='go_back').attrs['href'] = go_back_url
    
                response.content = str(BS)
            return response
    返回按钮

    参考:

    https://www.cnblogs.com/alex3714/articles/6661911.html

  • 相关阅读:
    js回调函数
    axios如何先请求A接口然后在请求B接口
    蓝桥杯省赛 区间移位(二分+玄学贪心)
    P1403 [AHOI2005]约数研究(筛法)
    P1029 最大公约数和最小公倍数问题(数论水题)
    洛谷P1147连续自然数和(前缀和)
    洛谷P1017进制转换(进制转换/取模)
    洛谷P1088火星人(stl/全排列)
    Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) D. Navigation System(最短路)
    Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) C. Remove Adjacent(贪心+暴力)
  • 原文地址:https://www.cnblogs.com/sss4/p/9364399.html
Copyright © 2011-2022 走看看