zoukankan      html  css  js  c++  java
  • Djang之基于角色的权限控制(RBAC)

    一、后端部分

    1. models设计

    实现:特定角色拥有访问特定url路径,角色关联用户,以此来控制用户的访问。

    如:管理员:可以访问所有的url地址,甲关联了管理员,则甲拥有访问所有url地址的权限,普通用户:只拥有访问查看数据(查看某个页面)的url地址,乙关联普通用户,乙就只拥有普通用户的权限

    2.models实现

    class Permission(models.Model):
        url = models.CharField(max_length=64, verbose_name='权限')
        title = models.CharField(max_length=32, verbose_name='标题')
    
        def __str__(self):
            return self.title
    
        class Meta:
            verbose_name_plural = '权限管理'
    
    
    class Role(models.Model):
        name = models.CharField(max_length=32, verbose_name='角色')
        permissions = models.ManyToManyField(Permission, verbose_name='角色拥有的权限', blank=True)
    
        def __str__(self):
            return self.name
    
        class Meta:
            verbose_name_plural = '角色管理'
    
    
    class User(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户名', unique=True)
        password = models.CharField(max_length=32, verbose_name='密码')
        roles = models.ManyToManyField(Role, verbose_name='用户的角色', blank=True)
    
        def __str__(self):
            return self.username
    
        class Meta:
            verbose_name_plural = '用户管理'
    models.py

    3. 将登陆成功的用户的权限(url地址)写入到session中

    from rbac import models
    from django.shortcuts import redirect, render, HttpResponse
    from django.conf import settings
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            obj = models.User.objects.filter(username=username, password=password).first()
            if not obj:
                error = '用户名或密码错误'
                return render(request, 'login.html', locals())
    
            # 获取权限的信息
            permission= obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                'permissions__title',
                                                                              ).distinct()
    
            # 获取登录用户的权限列表(能访问的url地址)
            request.session['permission'] = list(permission)
            request.session['is_login'] = 1
            return redirect('index')
    
        return render(request, 'login.html', locals())    
    views.py

    4. 白名单与免认证名单

    #白名单:无需登录,就可以访问的路径
    WHITE_LIST = [
        r'/login/',
        r'^/admin/',
    ]
    
    #免认证名单 登录之后的用户都可以访问的url
    PUBLIC_LIST = [
        r'/index/',
    ]
    settings.py

    5. 从中间件中获取request.session中的permission权限(url地址列表)

    from django.utils.deprecation import MiddlewareMixin
    from django.conf import settings
    from django.shortcuts import redirect, HttpResponse
    import re
    
    class AuthMiddleware(MiddlewareMixin):
        def process_request(self, request):
            url = request.path_info  # 当前页面的url地址
            # 白名单 :登陆、注册、admin
            for i in settings.WHITE_LIST: # WHITE_LIST是配置在settings.py文件中的地址白名单
                if re.match(i, url):
                    return
    
            # 登陆验证
            is_login = request.session.get('is_login')
            if is_login != 1:
                return redirect('login')
    
            # 免认证 登录之后所有人都能访问的地址如:后台首页
            for i in settings.PUBLIC_LIST:
                if re.match(i, url):
                    return
    
            # 权限验证 我们在登录函数中将当前登录用户中的所有权限(url地址列表)都放入到了session中,这里拿出来和当前的url地址进行匹配。
            permission = request.session.get('permission ')
            for i in permission:
                if re.match(r'^{}$'.format(i['url']), url):
                    return
            return HttpResponse('没有权限,请联系管理员!')
    middlewares/rbac.py

    二、前端部分

    6.  自定模板标签,渲染数据

    注意:模板标签存放的目录必须为tamplatetags

    # -*- coding: utf-8 -*-
    # __author__ = "maple"
    from django import template
    from django.conf import settings
    import re
    register = template.Library()
    @register.inclusion_tag('menu_tag.html') # menu_tag.html文件时配合该函数做模板渲染的,是该标签的一部分
    def menu(request):
        """
       当当前url地址与menu_list中的url地址能够匹配到时,给menu_list中    
       的匹配到的地址添加一个键值对{"class":"active"}
        """
        url = request.path_info
        # 添加激活的样式
        for i in menu_list:
            if re.match(f'^{i["url"]}$',url):
                i['class'] = 'active'
                break
        return {'menu_list':menu_list}
    
    # menu_list的数据格式如:
    #    [{'url':'/customer/list/'},{'url':'/customer/add/'},]
    # 假如当前url地址为:/customer/list/时
    #    则 menu_list中数据会变为:
    #    [{'url':'/customer/list/',"class":"active"},{'url':'/customer/add/'},]
    my_tags.py

    my_tags文件中通过装饰器渲染的标签内容

    <div class="static-menu">
        {% for menu in menu_list %}
            <a href="{{ menu.url}}" class="{{menu.class}}">{{ menu.title}}</a>
        {% endfor %}
    </div>
    menu_tag.html

    7. 应用自定义标签

        ...
    <div class="left-menu">
       <div class="menu-body">
            {% load my_tags %}
            {% menu request %}
    </div>
        ...    
    顶级模板文件中
  • 相关阅读:
    社区运营一点事
    从拉动APP下载谈运营
    c#基础学习(0702)之面向对象和方法重写概述
    c#基础学习(0706)之使用虚方法实现多态
    c#基础学习(0703)之string.Format格式化日期
    c#基础学习(0701)之一些简单的方法练习
    c#基础学习(0630)之面向对象总习
    c#基础学习(0629)之导出Excel方法
    c#基础学习(0628)之使用进程打开指定的文件、模拟磁盘打开文件
    c#基础学习(0627)之类型转换、算数运算符++、--
  • 原文地址:https://www.cnblogs.com/kindvampire/p/12173525.html
Copyright © 2011-2022 走看看