zoukankan      html  css  js  c++  java
  • 基于django内置的权限管理系统写一套自己的权限管理

    #基础知识
    #rest framwork 的内置admin的权限控制中,默认为每个model生成了3个权限: add update delete 
    #将信息保存在内置的content_type表中,表中保存了model所在的app 和model的三个权限
    #admin的权限管理系统由内置的三张表组成 user group permission  三张表之间的关系又由另外3张表来连接
    #他们的关系如下图
    
    
    
    #利用内置权限管理定制自己所需要的权限系统的方法
    #只需做一些稍微的修改,便可以使用内置的权限系统,为自己所用了
    
    #1 写自己的user表,继承AbstractUser,可以添加额外的字段,但默认已经有了用户名和密码
    class Manager(AbstractUser):
        mobile_number = models.CharField(max_length=20, verbose_name='手机号')
    
    #定制需要的登陆验证方法,默认的登陆验证是用户名和密码
    class CustomBackend(ModelBackend):
        """
        定义用户登录方式(手机号/邮箱登录)
        """
    
        def authenticate(self, request, username=None, password=None, **kwargs):
            try:
                manager = Manager.objects.get(Q(mobile_number=username) | Q(email=username))
                if manager.check_password(password):
                    return manager
                else:
                    raise ValidationError('用户名或密码错误', code=status.HTTP_400_BAD_REQUEST)
            except Exception as e:
                raise ValidationError('用户名或密码错误', code=status.HTTP_400_BAD_REQUEST)
                
    #由于默认只有增改删3个权限,我们要为它添加一个查看的权限,为此我们要添加自定义权限
    
    #在model中添加如下信息
    class Kids(models.Model):
        class Meta:
            permissions = (
                ('view_kids_list', '查看儿童信息表'),
            )
    
    #为用户分配权限
    #检验用户是否有的权限
    class KidsViewSet()
        permission_classes = (permissions.DjangoModelPermissions,)   #添加权限限制
        
        def list(self, request, *args, **kwargs):
            user = request.user
            if user.has_perm('kids.view_kids_list'):  #‘app名.权限名’
                return super(KidsViewSet, self).list(request, *args, **kwargs)
            else:
                data = {'detail': '没有权限'}
                return Response(data, status=status.HTTP_403_FORBIDDEN)
                
    #模仿admin修改密码  #加密以及解密方法
    class ManagerPasswordSerializer(serializers.Serializer):
        #添加额外字段的方法
        old_password = serializers.CharField(source='my_field')
        password = serializers.CharField(required=True)
    
        class Meta:
            model = Manager
            fields = '__all__'
    
            
    class ManagerPasswordViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
        """
            用户修改密码接口
            """
        queryset = Manager.objects.all()
        versioning_class = URLPathVersioning
        serializer_class = serializers.ManagerPasswordSerializer
    
        def update(self, request, version, *args, **kwargs):
            data = request.data
            new_password = data['password']
            old_password = data['old_password']
            from django.contrib.auth.hashers import check_password, make_password
            #验证旧密码是否正确
            username = request.user.username
            password = Manager.objects.filter(username=username).values('password')
            if check_password(old_password, password[0]['password']):
                #修改为新密码
                Manager.objects.filter(username=username).update(password=make_password(new_password))
                return Response('修改成功', status=status.HTTP_200_OK)
            else:
                return Response('密码输入错误', status=status.HTTP_400_BAD_REQUEST)
    #最后,只要给用户分配了相应的权限,就可以轻松的拥有一套权限系统啦
    
    
    #可以在用户登陆时给用户发送一个权限菜单
    
    #思路是:
    
    #1 新建一个菜单表,存储一级二级菜单的信息,每个对应content_type表中的每个model
    #2 用户登陆时获取用户的权限信息(具体形式是对哪些model的什么权限),在全部的权限(菜单表)中筛选出用户对哪些model具有权限,再拼接出url,
    #3 按菜单表中的信息形成嵌套层级关系,最后返回给用户菜单信息
    
    class Menu(models.Model):
        """
        用户权限菜单表
        """
        content_model = models.ForeignKey(ContentType, null=True)
        first_menu_name = models.CharField(max_length=100, null=True)
        second_menu_name = models.CharField(max_length=100, null=True)
        second_menu_parent = models.ForeignKey('Menu', null=True)
        second_menu_url = models.URLField(null=True)
        create_date = models.DateTimeField(verbose_name='申请日期', default=datetime.now, null=True)
    
        def __str__(self):
            return self.id
    
        class Meta:
            verbose_name = "菜单"
            verbose_name_plural = verbose_name
    
            
    def list(self, request, *args, **kwargs):
        # 获取域名和版本
        url = request.get_host()
        version = request.version
        # 用户所有的model权限
        permission_list = request.user.get_all_permissions()
        username = request.user.username
        user_model = set()
        for i in permission_list:
            model = i.split('_')[-1]
            user_model.add(model)
        user_model1 = list(user_model)
    
        first_info = Menu.objects.filter(content_model__model__in=user_model1, first_menu_name__isnull=False,
                                         second_menu_url__isnull=False).values('id', 'first_menu_name',
                                                                               'second_menu_url')
        second_info = Menu.objects.filter(content_model__model__in=user_model1, second_menu_name__isnull=False,
                                          ).values('second_menu_name', 'second_menu_url', 'second_menu_parent_id')
        # 拼接完整url,替换原来的url
        for i in first_info:
            if not i['second_menu_url']:
                continue
            i['second_menu_url'] = url + '/' + version + i['second_menu_url']
        for i in second_info:
            if not i['second_menu_url']:
                continue
            i['second_menu_url'] = url + '/' + version + i['second_menu_url']
    
        # 形成嵌套关系
        for i in first_info:
            i['child'] = []
            for j in second_info:
                if i['id'] == j['second_menu_parent_id']:
                    i['child'].append(j)
    
        first_info = list(first_info)
        first_info.append({'username': username})
        return Response(first_info)
    
    
    #缺陷: 权限只能限制到表的级别,不能限制到操作action的级别
  • 相关阅读:
    教师节快乐!
    来自学长同学分享的学习方法
    刘奕佳: 我的职校新生活 | 班级日常分享
    19级:班级日常分享 | 一天一瞬间
    珍惜、珍爱!
    19级:班级日常分享 | 一天一瞬间
    204787 ,194787 |0001 1131 0001 4226 7035 ![2480 ]
    1-N的自然数中,少了一个,找出这个数 小强斋
    获取某一天之前或者之后多少天的日期 小强斋
    获取某一天之前或者之后多少天的日期 小强斋
  • 原文地址:https://www.cnblogs.com/liuguniang/p/8087262.html
Copyright © 2011-2022 走看看