前言:

权限是什么?

对于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("\033[42;1m--------passed permission check----\033[0m")
            return True
        else:
            print("\033[41;1m ----- no permission ----\033[0m")
            print(request.user,perm_str)
            return False
    else:
        print("\033[41;1m ----- no matched permission  ----\033[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

 

posted on 2018-07-25 10:13  Martin8866  阅读(432)  评论(0编辑  收藏  举报