zoukankan      html  css  js  c++  java
  • 饮冰三年-人工智能-Python-35权限管理(万能的权限通用模块)

    我们分为两大块,第一块是自定义权限认证。可参考https://docs.djangoproject.com/en/2.2/topics/auth/customizing/  第二块是一个通用的模板

    自定义权限认证

     1:修改model.py类。主要是添加两个class

    from django.db import models
    from django.contrib.auth.models import User
    
    # Create your models here.
    
    from django.db import models
    from django.contrib.auth.models import (
        BaseUserManager, AbstractBaseUser,PermissionsMixin
    )
    
    
    class UserProfileManager(BaseUserManager):
        def create_user(self, email, name, password=None):
            """
            Creates and saves a User with the given email, date of
            birth 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 user
    
        def create_superuser(self, email, name, password):
            """
            Creates and saves a superuser with the given email, date of
            birth and password.
            """
            user = self.create_user(
                email,
                password=password,
                name=name,
            )
            user.is_superuser = True
            user.save(using=self._db)
            return user
    
    
    class UserProfile(AbstractBaseUser, PermissionsMixin):
        email = models.EmailField(
            verbose_name='email address',
            max_length=255,
            unique=True,
    
        )
        name = models.CharField(max_length=64, verbose_name="姓名")
        is_active = models.BooleanField(default=True)
        is_staff = models.BooleanField(default=True)
        #is_admin = models.BooleanField(default=False)
        role = models.ManyToManyField("Role", blank=True, null=True)
    
        objects = UserProfileManager()
    
        USERNAME_FIELD = 'email'
        REQUIRED_FIELDS = ['name']
    
        def get_full_name(self):
            # The user is identified by their email address
            return self.email
    
        def get_short_name(self):
            # The user is identified by their email address
            return self.email
    
        def __str__(self):              # __unicode__ on Python 2
            return self.email
    
    
        class Meta:
            permissions = (
                ('crm_table_list', '可以查看kingadmin每张表里所有的数据'),
                ('crm_table_list_view', '可以访问kingadmin表里每条数据的修改页'),
                ('crm_table_list_change', '可以对kingadmin表里的每条数据进行修改'),
                ('crm_table_obj_add_view', '可以访问kingadmin每张表的数据增加页'),
                ('crm_table_obj_add', '可以对kingadmin每张表进行数据添加'),
    
            )
    UserProfile、UserProfileManager

    2:修改admin.py 类

    from django.contrib import admin
    from CRM import models
    # Register your models here.
    
    
    
    
    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 ReadOnlyPasswordHashField
    
    from CRM.models import UserProfile
    
    
    class UserCreationForm(forms.ModelForm):
        """A form for creating new users. Includes all the required
        fields, plus a repeated password."""
        password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
        password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
    
        class Meta:
            model = UserProfile
            fields = ('email', 'name')
    
        def clean_password2(self):
            # Check that the two password entries match
            password1 = 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 password2
    
        def save(self, commit=True):
            # Save the provided password in hashed format
            user = super(UserCreationForm, self).save(commit=False)
            user.set_password(self.cleaned_data["password1"]) #把明文 根据算法改成密文
            if commit:
                user.save()
            return user
    
    
    class UserChangeForm(forms.ModelForm):
        """A form for updating users. Includes all the fields on
        the user, but replaces the password field with admin's
        password hash display field.
        """
        password = ReadOnlyPasswordHashField()
    
        class Meta:
            model = UserProfile
            fields = ('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 value
            return self.initial["password"]
    
    
    class UserProfileAdmin(BaseUserAdmin):
        # The forms to add and change user instances
        form = UserChangeForm
        add_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','groups')
    
    
    
    
    
    
    
    
    
    
    
    
    
    class CustomerAdmin(admin.ModelAdmin):
        list_display = ['id','name','source','contact_type','contact','consultant','consult_content','status','date']
        list_filter = ['source','consultant','status','date']
        search_fields = ['contact','consultant__name']
    
        #readonly_fields = ['status','contact']
        filter_horizontal = ['consult_courses',]
    
        actions = ['change_status',]
        def change_status(self,request,querysets):
            querysets.update(status=1)
    
    class CourseRecordAdmin(admin.ModelAdmin):
        list_display = ['class_grade','day_num','has_homework']
        #list_per_page = 2
        list_editable = ['has_homework',]
    admin.site.register(models.CustomerInfo,CustomerAdmin)
    admin.site.register(models.CustomerFollowUp)
    admin.site.register(models.ClassList)
    admin.site.register(models.Course)
    admin.site.register(models.Role)
    admin.site.register(models.Menus)
    admin.site.register(models.CourseRecord,CourseRecordAdmin)
    admin.site.register(models.StudyRecord)
    admin.site.register(models.Student)
    admin.site.register(models.UserProfile,UserProfileAdmin)
    admin.site.register(models.Branch)
    admin.site.register(models.ContractTemplate)
    admin.site.register(models.StudentEnrollment)
    admin.site.register(models.PaymentRecord)
    admin.py

    3:在setting.py文件中添加

    AUTH_USER_MODEL = 'CRM.UserProfile'

    权限通用的模板

    权限 = 一个url + 一种请求方法(get/post/put...) + 若干个请求参数

    一、权限组件与代码的实现

      我们把权限组件的实现分3步,权限条目的定义, 权限条目与用户的关联,权限组件与应用的结合

      1:权限条目的定义    

      perm_dic={
          'crm_table_index':['table_index','GET',[],{},],  #可以查看CRM APP里所有数据库表
          'crm_table_list':['table_list','GET',[],{}],    #可以查看每张表里所有的数据
          'crm_table_list_view':['table_change','GET',[],{}],#可以访问表里每条数据的修改页
          'crm_table_list_change':['table_change','POST',[],{}], #可以对表里的每条数据进行修改
        }  

      字典里的key是权限名, 一会我们需要用过这些权限名来跟用户进行关联

    • 后面values列表里第一个值如'table_index'是django中的url name,在这里必须相对的url name, 而不是绝对url路径,因为考虑到django url正则匹配的问题,搞绝对路径,不好控制。 
    • values里第2个值是http请求方法
    • values里第3个[]是要求这个请求中必须带有某些参数,但不限定对数的值是什么
    • values里的第4个{}是要求这个请求中必须带有某些参数,并且限定所带的参数必须等于特定的值

    我现在的需求是,只允许 用户访问客户来源为qq群且 已报名的 客户,你怎么控制 ?

    通过分析我们得出,这个动作的url为

    http://127.0.0.1:9000/kingadmin/crm/customer/?source=qq&status=signed
    

    客户来源参数是source,报名状态为status,那我的权限条目就可以配置成

     'crm_table_list':['table_list','GET',[],{'source':'qq', 'status':'signed'}]

      2:权限条目与用户的关联

      我们可以直接借用django自带的权限系统,借用它的 权限 与用户的关联 逻辑!将我们自定义权限条目添加到系统中

    通过model.py中的UserProfile的Meta

        class Meta:
            permissions = (
                ('crm_table_list', '可以查看kingadmin每张表里所有的数据'),
                ('crm_table_list_view', '可以访问kingadmin表里每条数据的修改页'),
                ('crm_table_list_change', '可以对kingadmin表里的每条数据进行修改'),
                ('crm_table_obj_add_view', '可以访问kingadmin每张表的数据增加页'),
                ('crm_table_obj_add', '可以对kingadmin每张表进行数据添加'),
    
            )
    Meta

      3:权限组件与应用的结合

       在KingAdmin中添加相应的权限组件permissions(权限判断:获--转--判--调)permission_list(权限列表) permission_hook(钩子函数,可以自定义过滤条件)

      在KingAdmin/views.py 中需要做权限判断的方法中,添加装饰器@permissions.check_permission

      部分关键代码  

    from django.urls import resolve
    from django.shortcuts import render,redirect,HttpResponse
    from KingAdmin.permission_list import perm_dic
    from django.conf import settings
    
    
    def perm_check(*args,**kwargs):
    
        request = args[0]
        resolve_url_obj = resolve(request.path)
        current_url_name = resolve_url_obj.url_name  # 当前url的url_name
        print('---perm:',request.user,request.user.is_authenticated,current_url_name)
        #match_flag = False
        match_results = [None,]
        match_key = None
        if request.user.is_authenticated is False:
             return redirect(settings.LOGIN_URL)
    
        for permission_key,permission_val in  perm_dic.items():
    
            per_url_name = permission_val[0]
            per_method  = permission_val[1]
            perm_args = permission_val[2]
            perm_kwargs = permission_val[3]
            perm_hook_func = permission_val[4] if len(permission_val)>4 else None
    
            if per_url_name == current_url_name: #matches current request url
                if per_method == request.method: #matches request method
                    # if not  perm_args: #if no args defined in perm dic, then set this request to passed perm
    
                    #逐个匹配参数,看每个参数时候都能对应的上。
                    args_matched = False #for args only
                    for item in perm_args:
                        request_method_func = getattr(request,per_method) #request.GET/POST
                        if request_method_func.get(item,None):# request字典中有此参数
                            args_matched = True
                        else:
                            print("arg not match......")
                            args_matched = False
                            break  # 有一个参数不能匹配成功,则判定为假,退出该循环。
                    else:#当列表为空的时候才走这里
                        args_matched = True
                    #匹配有特定值的参数
                    kwargs_matched = False
                    for k,v in perm_kwargs.items():
                        request_method_func = getattr(request, per_method)
                        arg_val = request_method_func.get(k, None)  # request字典中有此参数
                        print("perm kwargs check:",arg_val,type(arg_val),v,type(v))
                        if arg_val == str(v): #匹配上了特定的参数 及对应的 参数值, 比如,需要request 对象里必须有一个叫 user_id=3的参数
                            kwargs_matched = True
                        else:
                            kwargs_matched = False
                            break # 有一个参数不能匹配成功,则判定为假,退出该循环。
                    else:
                        kwargs_matched = True
    
                    #开始匹配自定义权限钩子函数
                    perm_hook_matched = True
                    if perm_hook_func:
                        perm_hook_matched = perm_hook_func(request)
    
    
                    match_results = [args_matched,kwargs_matched,perm_hook_matched]
                    print("--->match_results ", match_results)
                    if all(match_results): #都匹配上了
                        match_key = permission_key
                        break
    
        if all(match_results):
            app_name, *per_name = match_key.split('_')
            print("--->matched ",match_results,match_key)
            print(app_name, *per_name)
            perm_obj = '%s.%s' % (app_name,match_key)
            print("perm str:",perm_obj)
            if request.user.has_perm(perm_obj):
                print('当前用户有此权限')
                return True
            else:
                print('当前用户没有该权限')
                return False
    
        else:
            print("未匹配到权限项,当前用户无权限")
    
    
    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
    permissions
    from KingAdmin import permission_hook
    
    perm_dic= {
    
        #'crm_table_index': ['table_index', 'GET', [], {'source':'qq'}, ],  # 可以查看CRM APP里所有数据库表
        'CRM_table_list': ['table_obj_list', 'GET', [], {}],  # 可以查看每张表里所有的数据
        'CRM_table_list_view': ['table_obj_change', 'GET', [], {}],  # 可以访问表里每条数据的修改页
        'CRM_table_list_change': ['table_obj_change', 'POST', [], {}],  # 可以对表里的每条数据进行修改
        'CRM_table_obj_add_view': ['table_obj_add', 'GET', [], {}],  # 可以访问数据增加页
        'CRM_table_obj_add': ['table_obj_add', 'POST', [], {}],  # 可以创建表里的数据
    
    }
    permission_list
    def view_my_own_customers(request):
        print("running permisionn hook check.....")
        if str(request.user.id) == request.GET.get('consultant'):
            print("访问自己创建的用户,允许")
            return True
        else:
            return False
    permission_hook
    from django.db import models
    from django.contrib.auth.models import User
    
    # Create your models here.
    
    from django.db import models
    from django.contrib.auth.models import (
        BaseUserManager, AbstractBaseUser,PermissionsMixin
    )
    
    
    class UserProfileManager(BaseUserManager):
        def create_user(self, email, name, password=None):
            """
            Creates and saves a User with the given email, date of
            birth 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 user
    
        def create_superuser(self, email, name, password):
            """
            Creates and saves a superuser with the given email, date of
            birth and password.
            """
            user = self.create_user(
                email,
                password=password,
                name=name,
            )
            user.is_superuser = True
            user.save(using=self._db)
            return user
    
    
    class UserProfile(AbstractBaseUser, PermissionsMixin):
        email = models.EmailField(
            verbose_name='email address',
            max_length=255,
            unique=True,
    
        )
        name = models.CharField(max_length=64, verbose_name="姓名")
        is_active = models.BooleanField(default=True)
        is_staff = models.BooleanField(default=True)
        #is_admin = models.BooleanField(default=False)
        role = models.ManyToManyField("Role", blank=True, null=True)
    
        objects = UserProfileManager()
    
        USERNAME_FIELD = 'email'
        REQUIRED_FIELDS = ['name']
    
        def get_full_name(self):
            # The user is identified by their email address
            return self.email
    
        def get_short_name(self):
            # The user is identified by their email address
            return self.email
    
        def __str__(self):              # __unicode__ on Python 2
            return self.email
    
    
        class Meta:
            permissions = (
                ('CRM_table_list', '可以查看kingadmin每张表里所有的数据'),
                ('CRM_table_list_view', '可以访问kingadmin表里每条数据的修改页'),
                ('CRM_table_list_change', '可以对kingadmin表里的每条数据进行修改'),
                ('CRM_table_obj_add_view', '可以访问kingadmin每张表的数据增加页'),
                ('CRM_table_obj_add', '可以对kingadmin每张表进行数据添加'),
    
            )
    
    
    class Role(models.Model):
        """角色表"""
        name = models.CharField(max_length=64, unique=True)
        menus = models.ManyToManyField("Menus", blank=True)
    
        def __str__(self):
            return self.name
    
    class CustomerInfo(models.Model):
        """客户信息表"""
        name = models.CharField(max_length=64, default=None)
        contact_type_choices = ((0, 'qq'), (1, '微信'), (2, '手机'))
        contact_type = models.SmallIntegerField(choices=contact_type_choices, default=0)
        contact = models.CharField(max_length=64, unique=True)
        source_choices = ((0, 'QQ群'),
                          (1, '51CTO'),
                          (2, '百度推广'),
                          (3, '知乎'),
                          (4, '转介绍'),
                          (5, '其它'),
                          )
        source = models.SmallIntegerField(choices=source_choices)
        referral_from = models.ForeignKey("self", blank=True, null=True, verbose_name="转介绍",on_delete=models.CASCADE)
        consult_courses = models.ManyToManyField("Course", verbose_name="咨询课程")
        consult_content = models.TextField(verbose_name="咨询内容")
        status_choices = ((0, '未报名'), (1, '已报名'), (2, '已退学'))
        status = models.SmallIntegerField(choices=status_choices)
        consultant = models.ForeignKey("UserProfile", verbose_name="课程顾问",on_delete=None)
        id_num = models.CharField(max_length=128, blank=True, null=True)
        emergency_contact = models.PositiveIntegerField(blank=True, null=True)
        sex_choices = ((0, ''), (1, ''))
        sex = models.PositiveSmallIntegerField(choices=sex_choices, blank=True, null=True)
    
        date = models.DateField(auto_now_add=True)
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name = "客户信息"
            verbose_name_plural = "客户信息"
    
    class CustomerFollowUp(models.Model):
        """客户跟踪记录表"""
        customer = models.ForeignKey("CustomerInfo",on_delete=None)
        content = models.TextField(verbose_name="跟踪内容")
        user = models.ForeignKey("UserProfile", verbose_name="跟进人",on_delete=None)
        status_choices = ((0, '近期无报名计划'),
                          (1, '一个月内报名'),
                          (2, '2周内内报名'),
                          (3, '已报名'),
                          )
        status = models.SmallIntegerField(choices=status_choices)
        date = models.DateField(auto_now_add=True)
    
        def __str__(self):
            return self.content
    
    class Student(models.Model):
        """学员表"""
        customer = models.ForeignKey("CustomerInfo",on_delete=None)
        class_grades = models.ManyToManyField("ClassList")
    
        def __str__(self):
            return "%s" % self.customer
    class ClassList(models.Model):
        """班级列表"""
        branch = models.ForeignKey("Branch",on_delete=None)
        course = models.ForeignKey("Course",on_delete=None)
        class_type_choices = ((0, '脱产'), (1, '周末'), (2, '网络班'))
        class_type = models.SmallIntegerField(choices=class_type_choices, default=0)
        semester = models.SmallIntegerField(verbose_name="学期")
        contract_template = models.ForeignKey("ContractTemplate", blank=True, null=True,on_delete=None)
        teachers = models.ManyToManyField("UserProfile", verbose_name="讲师")
        start_date = models.DateField("开班日期")
        graduate_date = models.DateField("毕业日期", blank=True, null=True)
    
        def __str__(self):
            return "%s(%s)期" % (self.course.name, self.semester)
    
        class Meta:
            unique_together = ('branch', 'class_type', 'course', 'semester')
    
    class Branch(models.Model):
        """校区"""
        name = models.CharField(max_length=64,unique=True)
        addr = models.CharField(max_length=128,blank=True,null=True)
        def __str__(self):
            return self.name
    
    class Course(models.Model):
        """课程表"""
        name = models.CharField(verbose_name='课程名称', max_length=64, unique=True)
        price = models.PositiveSmallIntegerField()
        period = models.PositiveSmallIntegerField(verbose_name="课程周期(月)", default=5)
        outline = models.TextField(verbose_name="大纲")
    
        def __str__(self):
            return self.name
    
    class CourseRecord(models.Model):
        """上课记录"""
        class_grade = models.ForeignKey("ClassList",verbose_name="上课班级",on_delete=None)
        day_num = models.PositiveSmallIntegerField(verbose_name="课程节次")
        teacher = models.ForeignKey("UserProfile",on_delete=None)
        title = models.CharField("本节主题",max_length=64)
        content = models.TextField("本节内容")
        has_homework = models.BooleanField("本节有作业",default=True)
        homework = models.TextField("作业需求",blank=True,null=True)
        date = models.DateTimeField(auto_now_add=True)
        def __str__(self):
            return  "%s第(%s)节" %(self.class_grade,self.day_num)
    
        class Meta:
            unique_together = ('class_grade','day_num')
    
    class StudyRecord(models.Model):
        """学习记录表"""
        course_record = models.ForeignKey("CourseRecord",on_delete=None)
        student = models.ForeignKey("Student",on_delete=None)
    
        score_choices = ((100,"A+"),
                         (90,"A"),
                         (85,"B+"),
                         (80,"B"),
                         (75,"B-"),
                         (70,"C+"),
                         (60,"C"),
                         (40,"C-"),
                         (-50,"D"),
                         (0,"N/A"), #not avaliable
                         (-100,"COPY"), #not avaliable
                         )
        score = models.SmallIntegerField(choices=score_choices,default=0)
        show_choices = ((0,'缺勤'),
                        (1,'已签到'),
                        (2,'迟到'),
                        (3,'早退'),
                        )
        show_status = models.SmallIntegerField(choices=show_choices,default=1)
        note = models.TextField("成绩备注",blank=True,null=True)
    
        date = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
    
            return "%s %s %s" %(self.course_record,self.student,self.score)
    
    class Menus(models.Model):
        """动态菜单"""
        name = models.CharField(max_length=64)
        url_type_choices = ((0,'absolute'),(1,'dynamic'))
        url_type = models.SmallIntegerField(choices=url_type_choices,default=0)
        url_name = models.CharField(max_length=128)
    
        def __str__(self):
            return self.name
    
        class Meta:
            unique_together = ('name','url_name')
    
    class ContractTemplate(models.Model):
        """存储合同模板"""
        name = models.CharField(max_length=64)
        content = models.TextField()
        date = models.DateField(auto_now_add=True)
    
    class  StudentEnrollment(models.Model):
        """学员报名表"""
        customer = models.ForeignKey("CustomerInfo",on_delete=None)
        class_grade = models.ForeignKey("ClassList",on_delete=None)
        consultant = models.ForeignKey("UserProfile",on_delete=None)
        contract_agreed = models.BooleanField(default=False)
        contract_signed_date = models.DateTimeField(blank=True,null=True)
        contract_approved = models.BooleanField(default=False)
        contract_approved_date =  models.DateTimeField(verbose_name="合同审核时间", blank=True,null=True)
    
        class Meta:
            unique_together = ('customer','class_grade')
    
        def __str__(self):
            return "%s" % self.customer
    
    class PaymentRecord(models.Model):
        """存储学员缴费记录"""
        enrollment = models.ForeignKey(StudentEnrollment,on_delete=None)
        payment_type_choices = ((0,'报名费'),(1,'学费'),(2,'退费'))
        payment_type =  models.SmallIntegerField(choices=payment_type_choices,default=0)
        amount = models.IntegerField("费用",default=500)
        consultant = models.ForeignKey("UserProfile",on_delete=None)
        date = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return "%s" % self.enrollment
    model.py
    from django.shortcuts import render,redirect
    from django.contrib.auth import authenticate,login,logout
    # Create your views here.
    
    def acc_login(request):
        error_msg = ''
        if request.method == "POST":
            username = request.POST.get('username')
            password = request.POST.get('password')
    
            user = authenticate(username=username,password=password)
            if user:
                print("passed authencation",user)
                login(request,user)
                #request.user = user
    
                return  redirect( request.GET.get('next','/') )
            else:
                error_msg = "Wrong username or password!"
        return render(request, 'login.html', {'error_msg':error_msg})
    
    def acc_logout(request):
        logout(request)
        return redirect("/login/")
    view.py

  • 相关阅读:
    JDBC07-----代码重构之封装DBCUtils工具类
    JDBC06-----数据库连接池与配置文件
    JDBC05----事务与批处理
    JDBC04----预编译语句介绍
    JDBC03----DAO思想
    数据的序列化,持久化,归档
    苹果官方的图标大小的调整
    UIColletionView 的属性与常用方法介绍
    IOS学习笔记25—HTTP操作之ASIHTTPRequest
    IOS UI segmentedControl UISegmentedControl 常见属性和用法
  • 原文地址:https://www.cnblogs.com/YK2012/p/11844524.html
Copyright © 2011-2022 走看看