python---django中权限框架设计
生活随笔
收集整理的這篇文章主要介紹了
python---django中权限框架设计
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一:admin下的權(quán)限了解
推文:如何正確使用 Django的User Model
(一)默認權(quán)限表是在自帶auth模塊,中permission表中
可以使用has_perm方法獲取用戶是否有這個權(quán)限
(二)Django自定義權(quán)限
(1)添加表
from django.db import models from django.contrib.auth.models import (BaseUserManager, AbstractBaseUser,PermissionsMixin#BaseUserManager 用戶管理基類,用于創(chuàng)建用戶
#AbstractBaseUser 抽象類,聲明一些必須字段,不會自己生產(chǎn)表,繼承的子類才會,主要內(nèi)容:class Meta abstract=True
#PermissionMixin 權(quán)限管理類,也是抽象類 )class MyUserManager(BaseUserManager): #用于創(chuàng)建用戶,需要在settings文件中聲明def create_user(self, email, name, password=None):""" Creates and saves a User with the given email, date ofbirth and password.""" if not email:raise ValueError('Users must have an email address')user = self.model(email=self.normalize_email(email),name=name,)user.set_password(password)user.save(using=self._db)return userdef create_superuser(self, email, name, password):""" Creates and saves a superuser with the given email, date ofbirth and password.""" user = self.create_user(email,password=password,name=name,)user.is_superuser = Trueuser.save(using=self._db)return userclass UserProfile(AbstractBaseUser,PermissionsMixin): email = models.EmailField(verbose_name='email address',max_length=255,unique=True,)name = models.CharField(max_length=128)is_active = models.BooleanField(default=True)is_staff = models.BooleanField(default=True)# is_admin = models.BooleanField(default=False) #其中is_admin沒有作用,is_superuser才是設(shè)置超級用戶role = models.ManyToManyField("Role",blank=True) #,null=Truenull has no effect on ManyToManyField.,null對于manytomanyfield無作用,會報警objects = MyUserManager() #用戶管理類和自定義用戶表關(guān)聯(lián)USERNAME_FIELD = 'email'REQUIRED_FIELDS = ['name']def __str__(self):return self.emaildef get_full_name(self):return self.emaildef get_short_name(self):return self.email
class Meta:
permissions = ( #用于管理權(quán)限條目
('自定義權(quán)限名','解釋'),
)
?
(2)settings文件中設(shè)置
AUTH_USER_MODEL = 'repository.UserProfile' #上面的值表示Django應(yīng)用的名稱(必須位于INSTALLLED_APPS中)和你想使用的User模型的名稱。(3)在admin文件中設(shè)置展示內(nèi)容
from django import forms from django.contrib import admin from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.forms import ReadOnlyPasswordHashFieldfrom repository.models import UserProfileclass UserCreationForm(forms.ModelForm): #創(chuàng)建時顯示的表單信息"""A form for creating new users. Includes all the requiredfields, plus a repeated password.""" password1 = forms.CharField(label='Password', widget=forms.PasswordInput)password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)class Meta:model = UserProfilefields = ('email', 'name')def clean_password2(self): #對字段進行驗證# Check that the two password entries matchpassword1 = self.cleaned_data.get("password1")password2 = self.cleaned_data.get("password2")if password1 and password2 and password1 != password2:raise forms.ValidationError("Passwords don't match")return password2def save(self, commit=True): # Save the provided password in hashed formatuser = super().save(commit=False)user.set_password(self.cleaned_data["password1"])if commit:user.save()return userclass UserChangeForm(forms.ModelForm): #修改時顯示的表單信息"""A form for updating users. Includes all the fields onthe user, but replaces the password field with admin's password hash display field.""" password = ReadOnlyPasswordHashField() #密碼字段顯示時是hash加密只讀字段class Meta:model = UserProfilefields = ('email', 'password', 'name', 'is_active', 'is_superuser')def clean_password(self):# Regardless of what the user provides, return the initial value.# This is done here, rather than on the field, because the# field does not have access to the initial valuereturn self.initial["password"]class UserProfileAdmin(BaseUserAdmin): #用于注冊的表類# The forms to add and change user instancesform = UserChangeFormadd_form = UserCreationForm# The fields to be used in displaying the User model.# These override the definitions on the base UserAdmin# that reference specific fields on auth.User.list_display = ('email', 'name', 'is_superuser')list_filter = ('is_superuser',)fieldsets = ( #用于修改(None, {'fields': ('email', 'password')}),('Personal info', {'fields': ('name',)}),('Permissions', {'fields': ('is_active','is_staff','is_superuser','role','user_permissions','groups',)}),)# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin# overrides get_fieldsets to use this attribute when creating a user.add_fieldsets = ( #用于添加(None, {'classes': ('wide',),'fields': ('email', 'name', 'password1', 'password2')}),)search_fields = ('email',)ordering = ('email',)filter_horizontal = ('role','user_permissions',)# Now register the new UserAdmin... admin.site.register(UserProfile, UserProfileAdmin) # ... and, since we're not using Django's built-in permissions, # unregister the Group model from admin. admin.site.unregister(Group)?二:通用權(quán)限框架設(shè)計
(一)業(yè)務(wù)場景分析(如何去實現(xiàn)將不同權(quán)限分配給用戶)
python---CRM用戶關(guān)系管理
(二)權(quán)限管理分析
主要實現(xiàn):將權(quán)限列表定義出來,與角色(用戶組)相互關(guān)聯(lián)就可以
權(quán)限列表實現(xiàn):
?
?(三)實現(xiàn)方法
(1)定義權(quán)限列表文件,將權(quán)限列表定義。設(shè)置為裝飾器,根據(jù)每個用戶訪問的url去反解,獲取到對應(yīng)的權(quán)限列表名,從而去數(shù)據(jù)庫中獲取,使用has_prem獲取是否擁有權(quán)限。從而在用戶訪問url時進行判斷
?permission_list.py(這部分最好是放入數(shù)據(jù)庫中,可以改進)
from kingadmin import permission_hookperm_dict = {'repository_table_obj_list':['table_obj_list',"GET",[],{},permission_hook.view_my_own_customers],#第一個是url_name,第二個是訪問方式,第三個是訪問參數(shù)必須有的字段,第四個是字段中必須是指定的值,第五個是鉤子函數(shù),是對第三,第四參數(shù)的補充,實現(xiàn)動態(tài)驗證'repository_table_obj_change_view':['table_obj_change',"GET",[],{}],'repository_table_obj_change': ['table_obj_change', "POST", [], {}],'repository_table_obj_add_view': ['table_obj_add', "GET", [], {}],'repository_table_obj_add': ['table_obj_add', "POST", [], {}],'repository_table_obj_delete_view': ['table_obj_delete', "GET", [], {}],'repository_table_obj_delete': ['table_obj_delete', "POST", [], {}], } from django.conf.urls import url from kingadmin import viewsurlpatterns = [url(r"^login.html$",views.acc_login),url(r"^logout.html$", views.acc_logout,name="logout"),url(r"^$",views.app_index),url(r"^(\w+)/(\w+)/$",views.table_obj_list,name="table_obj_list"),url(r"^(\w+)/(\w+)/(\d+)/change/$", views.table_obj_change, name="table_obj_change"),url(r"^(\w+)/(\w+)/add/$", views.table_obj_add, name="table_obj_add"),url(r"^(\w+)/(\w+)/(\d+)/delete/$", views.table_obj_delete, name="table_obj_delete"), ] urls文件,可以知道對應(yīng)的url_name
resolve方法可以翻轉(zhuǎn)獲取url的數(shù)據(jù)
(2)permission文件,用于生成裝飾器,驗證權(quán)限列表
from .permission_list import perm_dict from django.conf import settings from django.core.urlresolvers import resolve from django.shortcuts import render,redirect,HttpResponse#對權(quán)限進行檢測 def perm_check(*args,**kwargs):request = args[0]resolve_url_obj = resolve(request.path) #1,獲取當前請求的urlcurrent_url_name = resolve_url_obj.url_name #2,把url解析成url_namematch_results = [None,]match_key = Noneif request.user.is_authenticated() is False: #3,進行用戶登錄驗證return redirect(settings.LOGIN_URL)for permssion_key,permssion_val in perm_dict.items():
#從權(quán)限列表中獲取url信息,以及鉤子函數(shù)(重點)per_url_name = permssion_val[0]per_method = permssion_val[1]per_args = permssion_val[2]per_kargs = permssion_val[3]per_hook_name = permssion_val[4] if len(permssion_val) > 4 else Noneif per_url_name == current_url_name: #4.匹配url_nameif per_method == request.method: #5.匹配訪問方法args_matched = False #用于匹配參數(shù)args,一次參數(shù)失敗,則失敗request_method_dict = getattr(request, per_method)for item in per_args: #6.匹配參數(shù)if request_method_dict.get(item,None):args_matched = Trueelse:args_matched = Falsebreak #一次匹配不上,就跳出else: #當不存在參數(shù),列表為空時args_matched = Truekwargs_matched = False #用于匹配特定的參數(shù)for k,v in per_kargs.items(): #7.匹配指定參數(shù)值arg_val = request_method_dict.get(k,None)if arg_val == str(v):kwargs_matched = Trueelse:kwargs_matched = Falseelse:kwargs_matched = Truehook_matched = Falseif per_hook_name: #8.匹配鉤子函數(shù)hook_matched = per_hook_name(request)else:hook_matched = Truematch_results = [args_matched,kwargs_matched,hook_matched]if all(match_results): #9.都匹配了 全局驗證,獲取了權(quán)限名,用于下面數(shù)據(jù)庫查詢match_key = permssion_keybreakif match_key:app_name,*per_name = match_key.split("_")perm_obj = "%s.%s"%(app_name,match_key)if request.user.has_perm(perm_obj): #10.數(shù)據(jù)庫查看用戶是否被分配該權(quán)限print("當前用戶有權(quán)限")return Trueelse:print("當前用戶沒有權(quán)限")return Falseelse:print("未匹配到權(quán)限項,當前用戶沒有權(quán)限")return False
#裝飾器函數(shù) def check_permission(func):def inner(*args,**kwargs):if not perm_check(*args,**kwargs):request = args[0]return render(request,"kingadmin/page_403.html")return func(*args,**kwargs)return inner
總結(jié):
def perm_check(*args,**kwargs):1.獲取當前請求的url,使用resolve解析獲取url_name2.匹配用戶是否登錄,使用user.is_authenticated方法3.使用url_name去權(quán)限列表permission_list文件中的權(quán)限列表中去匹配權(quán)限項4.將權(quán)限項解析分為,per_url_name(權(quán)限url_name),per_method (url訪問方法),per_args (獲取的參數(shù)名),per_kargs (獲取的參數(shù)值,字典),per_hook_name (獲取的權(quán)限鉤子函數(shù))5.驗證了上面的幾部分,獲取了權(quán)限名,然后去數(shù)據(jù)庫中獲取當前用戶是否擁有該權(quán)限,使用user.has_perm(權(quán)限名<注意:權(quán)限名是由數(shù)據(jù)表應(yīng)用加上權(quán)限名>)(3)鉤子函數(shù)案例(使當前用戶只能訪問自己的客戶)
def view_my_own_customers(request):if str(request.user.id) == request.GET.get('consultant'):return Trueelse:return False?
轉(zhuǎn)載于:https://www.cnblogs.com/ssyfj/p/9135479.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的python---django中权限框架设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搭建git服务器(权限管理)
- 下一篇: 疯狂秀才权限管理系统,开源了