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('没有权限')
    
  • 相关阅读:
    1.4.2.3. SETUP(Core Data 应用程序实践指南)
    1.4.2.2. PATHS(Core Data 应用程序实践指南)
    1.4.2.1. FILES(Core Data 应用程序实践指南)
    1.4.2. 实现 Core Data Helper 类(Core Data 应用程序实践指南)
    1.4.1. Core Data Helper 简介(Core Data 应用程序实践指南)
    1.4. 为现有的应用程序添加 Core Data 支持(Core Data 应用程序实践指南)
    1.3.2. App Icon 和 Launch Image(Core Data 应用程序实践指南)
    1.3.1. 新建Xcode项目并设置故事板(Core Data 应用程序实践指南)
    php验证邮箱是否合法
    如何使js函数异步执行
  • 原文地址:https://www.cnblogs.com/Kingfan1993/p/10022125.html
Copyright © 2011-2022 走看看