zoukankan      html  css  js  c++  java
  • 权限管理

    首先清楚两点:

    什么是权限一个包含正则表达式url就是一个权限

     rbac(role-based access control):以角色为基础的权限管理设计

    创建步骤:

     一、先创建一个 项目,建一个app01和rbac的应用

    在settings中进行配置:

      

     二、设计表结构 

    在models.py创建四个类,一共六张表

        用户表:User
        角色表:Role

        权限表:Permission
        权限组表:PermissionGroup
        角色表和权限表是多对多的关系(一个角色可以有多个权限,一个权限可以对应多个角色)role_permissions
        用户表和角色表是多对多的关系(一个用户可以有多个角色,一个角色有多个用户) user_roles

      

    from django.db import models
    
    
    class User(models.Model):
        name=models.CharField(max_length=32)
        pwd=models.CharField(max_length=32)
        roles=models.ManyToManyField(to="Role")
    
        def __str__(self): return self.name
    
    class Role(models.Model):
        title=models.CharField(max_length=32)
        permissions=models.ManyToManyField(to="Permission")
    
        def __str__(self): return self.title
    
    class Permission(models.Model):
        title=models.CharField(max_length=32)
        url=models.CharField(max_length=32)
    
        action=models.CharField(max_length=32,default="")
        group=models.ForeignKey("PermissionGroup",default=1) #一个组有多个权限,外键放在这里
        def __str__(self):return self.title
    
    
    
    class PermissionGroup(models.Model):
        title = models.CharField(max_length=32)
    
        def __str__(self): return self.title
    rbac/models.py

    具体分析为什么要和权限组表呢在permission表中添加action字段并关联一张permissiongroup表呢?

    1、我们一般是先看到的是列表页面,在这个页面上是否显示添加,是否显示编辑,是否显示删除,都是需要判断的
       有无添加权限,有无删除权限,有无编辑权限,我们可以给每一个url一个action

    dict = {
        1:{                   action
              /userinfo/            list
           /userinfo/add/       add
           /userinfo/del(d+)/    del 
           /userinfo/edit(d+)/    edit
        }
      }

    不仅在列表页面需要知道他有那些权限,在其他页面也知道他有哪些权限
    所以上面的方案还是有点不好,那么我们采取下面的方案。将action取出来放在一个列表里面

    dict = {
          1:{
                  "actions":["list","add","del","edit"]
                 urls:[
                    "/userinfo/",
                    "/userinfo/add"/,
                    "/userinfo/del(d+)/ ",
                    "/userinfo/edit(d+)/ ",
                  ]    
            }
          2:{
               "codes":{"list","add","del","edit"}
                urls:[
                     "/order",
                     "/order/add"/,
                      "/order/del(d+)/ ",
                     "/order/edit(d+)/ ",
                   ]    
           }
    }   

    把这个字典存到session中
    当你访问页面的时候我就知道你有什么权限
    一个url对应一个action
    多个url对应一个组

    注意:
      关联字段 null = True        数据库用的时候可以为空
      关联字段 blank = True     admin用的时候可以为空

    三、通过django-admin录入权限数据

    - 先创建一个超级用户 python3 manage.py createsuperuser
    - 用户名 zh
    - 密码 zh123456

    注册表

    #在rbac/models.py中注册表
    from django.contrib import admin
    from .models import *
    
    class PerConfig(admin.ModelAdmin):
        list_display = ["title","url","group","action"]
    admin.site.register(User)
    admin.site.register(Role)
    admin.site.register(Permission,PerConfig)
    admin.site.register(PermissionGroup)

    四、编写登录

    1.编写登录
    2.如果用户验证成功就设置session
    3.先查出当前用户的所有的权限,注册到session中

    from rbac.service.perssions import *
    
    def login(request):
    
        if  request.method=="POST":
    
            user=request.POST.get("user")
            pwd=request.POST.get("pwd")
            user=User.objects.filter(name=user,pwd=pwd).first()
            #如果登录成功
            if user:
                #在session中注册用户ID
                request.session["user_id"]=user.pk
    
                # 查询当前登录用户的所有权限,注册到session中
                initial_session(user,request)
    
                return HttpResponse("登录成功!")
    
        return render(request,"login.html")
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>
    
    <h4>登录页面</h4>
    
    <form action="" method="post">
        {% csrf_token %}
        
        用户名:<input type="text" name="user">
        密码:<input type="password" name="pwd">
        <input type="submit">
    </form>
    
    
    </body>
    </html>
    login.html

    rbac/service/permissions.py

    # 查询当前登录用户的所有权限,注册到session中,以下打印以egon登录为例,他只有一个查看的权限;/users/
    def initial_session(user,request):
        # #方案1 拿到权限列表,直接注册到session中
        # permissions = user.roles.all().values("permissions__url").distinct()
        # # [{},{}]
        # permission_list = []
        #
        # for item in permissions:
        #     permission_list.append(item["permissions__url"])
        # print(permission_list)   # ['/users/']
        #
        # request.session["permission_list"] = permission_list
    
        ##方案2
        #重构数据结构 (已重构表结构 :为Permission表加了一个字段action,外键关联一个表group)
        permissions = user.roles.all().values("permissions__url","permissions__group_id","permissions__action").distinct()
        print("permissions",permissions) #查看egon的权限为例它只有一个权限,列表中只有一个字典
        #permissions <QuerySet [{'permissions__url': '/users/', 'permissions__group_id': 1, 'permissions__action': 'list'}]>
    
        permission_dict={}
        for item in permissions:
            gid=item.get('permissions__group_id')
    
            if not gid in permission_dict:  # 如果组号不在字典里添加组号
    
                permission_dict[gid]={
                    "urls":[item["permissions__url"],],
                    "actions":[item["permissions__action"],]
                }
            else: #组号在字典中的话说明是同一个组,直接添加内容
                permission_dict[gid]["urls"].append(item["permissions__url"])
                permission_dict[gid]["actions"].append(item["permissions__action"])
    
    
        print(permission_dict)     #{
        #                             1: {
        #                           'urls': ['/users/'],
        #                           'actions': ['list']}},        构建的数据结构: 字典中-以组号为键,字典为值
        request.session['permission_dict']=permission_dict
    
        # 注册菜单权限
        permissions = user.roles.all().values("permissions__url","permissions__action","permissions__title").distinct()
        print("permissions",permissions)
    
        menu_permission_list=[]
        for item in permissions:
            if item["permissions__action"]=="list":
                menu_permission_list.append((item["permissions__url"],item["permissions__title"]))
    
        print(menu_permission_list)
        request.session["menu_permission_list"]=menu_permission_list

    通过以上设置,在用户登录成功后我们就能通过requset.actions查看用户有哪些操作权限。

    五、基于中间件的权限校验

    在settings中添加中间件

     

      

     rbac/service/rbac.py

    class ValidPermission(MiddlewareMixin):
    
        def process_request(self,request):
    
            # 拿到当前访问的路径,登录为例
            current_path = request.path_info
            print(current_path)   #/login/
    
            # 检查是否属于白名单,不然连登录注册的界面都进不去
            valid_url_list=["/login/","/reg/","/admin/.*"]
            # "/admin/.*" 的 .* 表示只要是admin开头就是,后面不管跟什么,因为我们在访问
            #/admin/的时候会自动跳转到 /admin/login/?next=/admin/ 这个路径下
    
            #如果访问的路径属于白名单,正常访问
            for valid_url in valid_url_list:
                ret=re.match(valid_url,current_path)
                if ret:
                    return None
    
            # 校验是否登录,这个user_id是用户登录时注册到session中的
            user_id=request.session.get("user_id")
            #如果没有登录,返回登录界面
            if not user_id:
                return redirect("/login/")
    
            ##校验权限2
    
            permission_dict=request.session.get("permission_dict")
    
            for item in permission_dict.values():   #循环字典里面的值  也就是字典 {1: { 'urls': ['/users/'],'actions': ['list']}}中键1所对应的值
                  urls=item['urls']                    #取出urls的值['/users/']
                  for reg in urls:                     #循环取出['/users/'] 里面的值,列表里面不止一个值,在这里登录人只有一个权限所以只有一个值
                      reg="^%s$"%reg                   #reg ="^/users/$"
                      ret=re.match(reg,current_path)   #和当前访问路径做匹配,也就是登录成功后所访问的路径,这里以访问/users/为例
                      if ret:
                          print("actions",item['actions'])    #actions ['list']
                          request.actions=item['actions']     #重构数据结构只为拿到用户对访问的表拥有增删改查的哪些权限,添加到request中
                          return None   #匹配成功,正常访问
    
            return HttpResponse("没有访问权限!")

    rbac/templatetags/my_tags.py

    from django import template
    
    register=template.Library()
    
    @register.inclusion_tag("rbac/menu.html")
    def get_menu(request,):
        # 获取当前用户可以放到菜单栏中的权限
        menu_permission_list = request.session["menu_permission_list"]
    
        return {"menu_permission_list":menu_permission_list}

    六、表单的增删改以及查看权限

    app01/views.py

    from django.shortcuts import render,HttpResponse
    
    from rbac.models import *
    
    class Per(object):
        def __init__(self,actions):
            self.actions=actions
        def add(self):
            return "add" in self.actions
        def delete(self):
            return "delete" in self.actions
        def edit(self):
            return "edit" in self.actions
        def list(self):
            return "list" in self.actions
    
    def users(request):
    
        user_list=User.objects.all()
    
        # permission_list=request.session.get("permission_list")
        #print(permission_list)
    
        # 查询当前登录人得名字
    
        id=request.session.get("user_id")
        user=User.objects.filter(id=id).first()
    
        per=Per(request.actions)
    
        return render(request,"rbac/users.html",locals())
    
    
    import re
    def add_user(request):
    
        return HttpResponse("add user.....")
    
    def del_user(request,id):
    
        return HttpResponse("del"+id)
    
    def roles(request):
    
        role_list=Role.objects.all()
        per = Per(request.actions)
        return render(request,"rbac/roles.html",locals())
    
    
    from rbac.service.perssions import *
    
    def login(request):
    
        if  request.method=="POST":
    
            user=request.POST.get("user")
            pwd=request.POST.get("pwd")
    
            user=User.objects.filter(name=user,pwd=pwd).first()
            #如果登录成功
            if user:
                #在session中注册用户ID
                request.session["user_id"]=user.pk
    
                # 查询当前登录用户的所有权限,注册到session中
                initial_session(user,request)
    
                return HttpResponse("登录成功!")
    
        return render(request,"login.html")

     相关html文件

    rabc/templates/rabc/base.html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
        <style>
            *{
                margin: 0;
                padding: 0;
            }
            .header{
                width: 100%;
                height: 60px;
                background-color: #336699;
            }
    
            .menu{
                background-color: bisque;
                position: fixed;
                top: 60px;
                bottom: 0px;
                left: 0px;
                width: 200px;
            }
    
            .content{
                position: fixed;
                top: 60px;
                bottom: 0;
                right: 0;
                left: 200px;
                overflow: auto;
                padding: 30px;
    
            }
    
            .menu_btn{
                font-size: 15px;
                text-align: center;
                padding: 30px 0;
    
            }
    
            .header .title{
                color: white;
                font-size: 18px;
                margin-right: 20px;
                font-weight: 100;
            }
        </style>
    </head>
    <body>
    
    <div class="header">
        <p class="title pull-right">{{ user.name }}</p>
    </div>
    <div class="contain">
            {% load my_tags %}
            <div class="menu">
                 {% get_menu request %}
            </div>
            <div class="content">
            {% block con %}
    
            {% endblock %}
    
            </div>
    </div>
    
    </body>
    </html>

    rabc/templates/rabc/menu.html

    <div>
    
         {% for item in menu_permission_list %}
              <p class="menu_btn"><a href="{{ item.0 }}">{{ item.1 }}</a></p>
         {% endfor %}
    
    </div>

    rabc/templates/rabc/users.html

    {% extends 'base.html' %}
    
    {% block con %}
    
        <h4>用户列表</h4>
    {#    {% if "users/add" in permissions_list %} 在重构数据结构后这一句用下面一句代替#}
        {% if per.add %}    <!--如果有添加用户的权限就显示添加用户的按钮-->
        <a href="/users/add/" class="btn btn-primary">添加用户</a>
        {% endif %}
        <table class="table table-bordered table-striped">
            <thead>
                  <tr>
                       <th>序号</th>
                       <th>姓名</th>
                       <th>角色</th>
                       <th>操作</th>
                  </tr>
            </thead>
           <tbody>
                {% for user in user_list %}
                <tr>
                     <td>{{ forloop.counter }}</td>
                     <td>{{ user.name }}</td>
                     <td>
                         {% for role in user.roles.all %}
                         {{ role.title }}
                         {% endfor %}
                     </td>
    
                     <td>
                         <a href="/users/delete/{{ user.pk }}" class="btn btn-danger">删除</a>
                         <a href="" class="btn btn-warning">编辑</a>
                     </td>
                </tr>
                {% endfor %}
    
           </tbody>
        </table>
    
    {% endblock %}

    rabc/templates/rabc/role.html

    {% extends 'base.html' %}
    
    {% block con %}
        <h4>角色列表</h4>
    
        {% if per.add %}
            <a href="" class="btn btn-primary">添加角色</a>
        {% endif %}
    
        <table class="table table-bordered table-striped">
            <tbody>
            {% for role in role_list %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ role.title }}</td>
    
                    <td>
                        <a href="/users/delete/{{ user.pk }}" class="btn btn-danger">删除</a>
                        <a href="" class="btn btn-warning">编辑</a>
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    
    {% endblock %}

    以上所用url

    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^users/$', views.users),
        url(r'^users/add', views.add_user),
        url(r'^users/delete/(d+)', views.del_user),
        url(r'^roles/', views.roles),
        url(r'^login/', views.login),
    ]

    相关博客1

    相关博客2

  • 相关阅读:
    no.5.print sum
    0.1 hint crack
    no.4 抽奖测试
    no2.crossdomain.xml批量读取(待完善)
    no.1
    day7-读写分离
    day6-主从
    day5-备份
    day4-用户授权
    Day3-体系结构+查询+导入/出
  • 原文地址:https://www.cnblogs.com/zh-xiaoyuan/p/12878137.html
Copyright © 2011-2022 走看看