TOP

Django_rbac_demo 权限控制组件框架模型

rbac 权限控制组件

  • 基于角色的权限控制
  • 本质每个权限即为一个 URL

项目组件结构

表结构

Role (title, permission) -(ManyToManyField)-   User   (name, pwd, roles)  

     |                        

(ManyToManyField)

     |                                 

Permission (title, url)

 实际生成表 及 测试数据

Django_rbac/ rbca/models.py

from django.db import models

# Create your models here.


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)

    def __str__(self):return self.title
View Code

核心代码部分

Django_rbac/ rbac/service/permission.py 

  用于获取当前用户的权限信息

"""
为了解耦,将处理权限的代码保存在组件里面
"""


def initial_session(user,request):
    # 查看当前用户的所有的权限
    # 因为会有values 的原理会导致有重复需要去重
    ret = user.roles.all().values("permissions__url").distinct()
    permission_list = []
    # 将所有的权限保存在一个列表里面,稍微处理下数据便于操作
    for i in ret:
        permission_list.append(i["permissions__url"])
    # 把用户的用户权限保存在 session 里面
    request.session["permission_list"] = permission_list

Django_rbac/rbac/service/rbca.py 

  基于当前用户的权限信息对来访请求进行逻辑判断筛选返回结果

    为了不冗余代码写在中间件中,对每一次的请求都做计算

    因中间件的工作机制导致所有的请求都被计算,需要对特殊的 URL 进行特殊处理

import re
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect
"""
写在中间件里面可以完全避免每次都要重复校验的问题
在请求来的时候进行校验,因此要写在 process_request 方法里面
"""


class ValidPermission(MiddlewareMixin):
    def process_request(self,request):
        # 当前访问路径
        current_path = request.path_info
        """
        检查是否属于白名单
            admin 的内部流程 
                不允许一上来就访问首页,必须要跳转到 登陆页面
                http://127.0.0.1:8000/admin/login/?next=/admin/
                第二次跳转到登录页面的请求如果没有被定义可通过就会被拦截
                无法只使用 admin 为过滤选项
                不能用 in 单纯的判断,还是要用到正则处理
                需要放过所有 admin 开头的 url 
        """
        valid_url_list = ["/login/","/reg/","/admin/.*"]
        for valid_url in valid_url_list:
            ret = re.match(valid_url,current_path)
            if ret:
                # 中间件 return None 表示这个中间件已经执行完毕
                return None

        """
        校验是否登录
            对于没有登陆的用户返回报错应该是让他去登陆
        """
        user_id = request.session.get("user_id")
        if not user_id:
            return redirect("/login/")

        """
        校验权限
            在编辑,以及删除页面的时候 url 不是固定的,
            会有内含的参数,因此权限列表里面不能仅仅是写死的url
            也不能再单纯的用 in 来判断。还是要靠正则来处理
            将权限列表里面的权限信息用 正则表达式来保存
            然后对访问页面进行验证是否可以通过来处理
        """
        permission_list = request.session.get("permission_list",[]) 
        flag = False
        for permission in permission_list:
            permission = f"^{permission}$"
            ret = re.match(permission, current_path)
            if ret:
                flag = True
                break
        if not flag:
            return HttpResponse("没有访问权限! ")
        return None

   不要忘记注册在 Django_rbac\Django_rbac\settings.py 里面 

 

其他app 引用使用

Django_rbac/app01/views.py 

from django.shortcuts import render,HttpResponse
import re
# Create your views here.
from rbac.models import *
from rbac.service.perssions import initial_session


def users(request):
    user_list=User.objects.all()
    return render(request,"users.html",locals())


def add_user(request):
    permission_list = request.session["permission_list"]
    return HttpResponse("add user.....")


def roles(request):
    role_list=Role.objects.all()
    return render(request,"roles.html",locals())


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:
            # 把用户的id 保存在 session 里面
            request.session["user_id"] = user.pk
            # 查询当前用户的所有的权限
            initial_session(user,request)
            return HttpResponse("登录成功!")
    return render(request, "login.html",locals())

测试页面代码

  这个就比较随意了,看个结果而已。

Django_rbac\templates\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>
View Code

Django_rbac\templates\roles.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>
<ul>
    {% for role in role_list %}
    <p>{{ role }}</p>
    {% endfor %}

</ul>

</body>
</html>
View Code

Django_rbac\templates\users.html

 1 <!DOCTYPE html>
 2 <html lang="zh-CN">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7 </head>
 8 <body>
 9 
10 <h4>用户列表</h4>
11 <ul>
12     {% for user in user_list %}
13     <p>{{ user }}</p>
14     {% endfor %}
15 
16 </ul>
17 
18 </body>
19 </html>
View Code

 

posted @ 2018-12-24 16:22  羊驼之歌  阅读(713)  评论(0编辑  收藏  举报