基于django内置的权限管理系统写一套自己的权限管理

Posted 柳姑娘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于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的级别

 

以上是关于基于django内置的权限管理系统写一套自己的权限管理的主要内容,如果未能解决你的问题,请参考以下文章

RBAC——权限六张表

Django—内置用户权限管理

django(权限认证)系统—— 基于Authentication backends定制

Django(59)验证和授权

Django内置权限系统源码解读

django实现不同用户查看不同菜单