zoukankan      html  css  js  c++  java
  • Django实现Rbac权限管理

    权限管理

    权限管理是根据不同的用户有相应的权限功能,通常用到的权限管理理念Rbac.

    Rbac

    基于角色的权限访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系可以建立起来以囊括更广泛的客观情况。

    数据库表体现

    在后端数据库rbac的表现是,一张用户表,一张职位表,还有一张权限表,用户多对多职位表,因为同一个人可能拥有多个职位,职位表多对多权限权限表,一个职位可拥有多个权限,权限在web的体现就是url地址,你必须有相对url的权限才能访问页面,从而限制你的功能

    简单rbac表例子:

    可以看出对于关于用户的增删改查功能的权限就是你能访问对应的url。例如boss职位我可以给他分配所有的权限,在职位权限表中可以看出boss拥有所有的权限。

    如何实现

    现在你可以给一个用户指定职位以及职位的权限,那么django中如何实现权限管理。首先你的知道django的运作流程,看下面的图:

    用过django框架的很容易看懂这张图,简单来说流程如下:

    1. wsgiref模块负责接受和发送底层的socket消息
    2. 中间件为全局钩子对django的输入和输出进行操作
    3. 路由系统根据url执行相应的视图函数
    4. 视图函数调用数据库和模板语言渲染html文件返回给前段

    所以我们可以自己写一个中间件来实现权限管理

    实现原理分析

    登录后要做的事:

    1. 登录成功后从数据库中获取当前用户的所有权限,也就是所有的url地址
    2. 利用session的特点将登录用户的所有url地址以键值对的形式保存

    写一个中间件实现以下功能:

    1. 除了访问白名单中的url,都必须校验权限
    2. 根据请求的session判断当前用户的权限即获取能访问得url,没有登录则获取不到
    3. 校验通过则运行执行django下一步流程
    4. 校验不通过则返回没有权限提示,或返回登录页面

    具体实现

    数据库

    from django.db import models
    
    # Create your models here.
    class Permission(models.Model):
        title = models.CharField(max_length=22)
        url = models.CharField(max_length=32)
    
        def __str__(self):
            return self.title
        class Meta:
            verbose_name ='权限'
            verbose_name_plural=verbose_name
    
    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
        roles = models.ManyToManyField(to='Role')
        class Meta:
            verbose_name ='用户'
            verbose_name_plural=verbose_name
        def __str__(self):
            return self.username
    
    class Role(models.Model):
        title = models.CharField(max_length=32)
        permissions =models.ManyToManyField(to='Permission',null=True,blank=True)
        class Meta:
            verbose_name ='角色'
            verbose_name_plural=verbose_name
        def __str__(self):
            return self.title
    

    登录校验的中间件

    from django.utils.deprecation import MiddlewareMixin
    import re
    from django.shortcuts import redirect
    class ValidLogin(MiddlewareMixin):
        def process_request(self,request):
            # 获取当前请求的url
            now_url = request.path_info
            wirte_url = ['admin/.*','login/']
            print(now_url)
            for url in wirte_url:
                if re.match(r'^/{}$'.format(url),now_url):
                    print('白名单通过')
                    return
            if request.session.get('user',''):
                print(request.session.get('user',''))
                print('已经登录')
                return
            else:
                next_url = '/login/?next='+now_url
                print(next_url)
                return redirect(next_url)
    

    登录视图

    from django.shortcuts import render,HttpResponse,redirect
    from django.http import JsonResponse
    
    # Create your views here.
    from rbac.models import UserInfo,Permission,Role
    
    def login(request):
        ret = {'ret':0}
        #获取因权限不足跳转到登录页面的原url,获取不到默认/customer/list/
        next_url = request.GET.get('next','/customer/list/')
        if request.method=='POST':
            #post请求,获取前端发送的账号和密码
            name = request.POST.get('email')
            pwd = request.POST.get('pwd')
            #根据获取到的账号密码去数据库筛选
            user_obj = UserInfo.objects.filter(username=name,password=pwd).first()
            if user_obj:
                ret={'ret':1}
                ret['url']=next_url
                # 如果筛选成功则跨边将用户所有的权限url取出来
                permission_queryset = user_obj.roles.all().filter(permissions__isnull=False).values_list('permissions__url')
                #利用生成器保存url
                permission_list = [i[0] for i in permission_queryset]
                #设置到session中
                request.session['permission_list'] = permission_list
            else:
                ret['msg']='账号密码错误'
            return JsonResponse(ret)
        #如果是get请求直接返回页面
        return render(request,'login.html')
    
    def logout(request):
        request.session.flush()
        return redirect('login')
    

    中间件

    class RBACMiddleware(MiddlewareMixin):
        def process_request(self, request):
            #白名单url
            wirte_url = [reverse('login'),reverse('logout')]
            #获取当前的url
            current_url = request.path_info
            print('当前url',current_url)
            #如果当前请求的url是白名单的url直接放行:
            for url in wirte_url:
                if re.match(r'^{}$'.format(url),current_url):
                    print('白名单通过')
                    return
            #否则判断当前请求url是否在当前登录的用户的权限url中
            #获取session中保存的用户权限url表
            permission_list = request.session.get('permission_list',[])
            for url in permission_list:
                if re.match(r'^{}$'.format(url),current_url):
                    print(permission_list)
                    print('权限通过')
                    return
            else:
                return HttpResponse('没有权限')
    
  • 相关阅读:
    [转载]setup factory使用方法
    MFC中调用WPF教程
    Reduce the Number of SQL Statements
    Library Cache Hit Ratio
    Seconds in wait
    PX Deq: Execute Reply等待事件
    RoundTrip Time
    Changing an Init.ora Parameter
    PX qref latch等待事件
    提高DBWR进程的吞吐量
  • 原文地址:https://www.cnblogs.com/Kingfan1993/p/10022125.html
Copyright © 2011-2022 走看看