首页 > 其他 > 详细

权限管理

时间:2020-05-15 20:55:34      阅读:40      评论:0      收藏:0      [点我收藏+]
首先清楚两点:

什么是权限一个包含正则表达式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

通过以上设置,在用户登录成功后我们就能通过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("没有访问权限!")

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

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()

    id=request.session.get("user_id")
    user=User.objects.filter(id=id).first()

    per=Per(request.actions)

    return render(request,"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,"roles.html",locals())  

 相关html文件

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> .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; } </style> </head> <body> <div class="header"> <p>{{ user.name }}</p> </div> <div class="contain"> <div class="menu">11</div> <div class="content"> {% block con %} {% endblock %} </div> </div> </body> </html>

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 %}

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

权限管理

原文:https://www.cnblogs.com/zh-xiaoyuan/p/12878137.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!