权限,锁定解锁用户接口,发送短信接口,drf部分源码分析APIView源码,新的Request对象,序列化类之 many=True 作用

Ⅰ 权限

【一】ACL(Access Control List,访问控制列表)

#  ACL(Access Control List,访问控制列表)
	将用户直接与与权限对接
    permission表
    id   user_id     权限名
    1    1           开直播
    2    1           评论

【二】RBAC(Role-Based Access Control,基于角色的访问控制)

  • 将用户与角色对接,然后角色与对象的权限对接
# 将用户与角色对接,然后角色与对象的权限对接

RBAC  是基于角色的访问控制(Role-Based Access Control )在 RBAC  中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

【三】ABAC(Attribute-Based Access Control,基于属性的访问控制)

#  ABAC(Attribute-Based Access Control,基于属性的访问控制)
ABAC(Attribute-Based Access Control,基于属性的访问控制),又称为PBAC(Policy-Based Access Control,基于策略的访问控制),CBAC(Claims-Based Access Control,基于声明的访问控制)。

传统的ACL、RBAC的架构是{subject,action,object},而ABAC的架构是{subject,action,object,contextual}且为他们添加了parameter(参数)。

subject属性:比如用户的年龄、部门、角色、威望、积分等主题属性。

action属性:比如查看、读取、编辑、删除等行为属性。

object属性:比如银行账户、文章、评论等对象或资源属性。

contextual属性:比如时段、IP位置、天气等环境属性

【四】补充:auth的user表,密码加密-->同样的明文,加密后 密文不一样

# auth的user表,密码加密-->同样的明文,加密后 密文不一样
	-pbkdf2_sha256:加密方式
    -600000:过期时间
    -uxJKoercOSxrWD1nwEitF8:盐
    -7GKS8QnEMPkxbQYRrJRwQg1vtS+XrzER+j/JAkM+1/U= :密文pbkdf2_sha256$600000$uxJKoercOSxrWD1nwEitF8$7GKS8QnEMPkxbQYRrJRwQg1vtS+XrzER+j/JAkM+1/U=
    
    
    auth的user表的对象有俩方法
    	# from django.contrib.auth.hashers import check_password  校验密码
    	user.check_password(明文密码)
        
        
        # from django.contrib.auth.hashers import make_password  转化为密文
        make_password(明文密码)-->User.object.create_user()
        
        
        
# 使用
class User(models.Model):

    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)  # 没有加密--明文
    age = models.CharField(max_length=32)
    
    @classmethod
    def create_user(self, username, password):
        password=make_password(password)
        self.objects.create( password=密文密码)

User.create_user()

【五】 django 的 自带admin-->后台管理--6张表实现rbac权限控制

#   django 的 自带admin--》后台管理--6张表实现rbac权限控制   具体点就是:rbac+acl
	-admin+auth--->有rbac的权限
    
    -分析:通过那些表实现rbac
    	-用户表;auth-user表:auth_user
        	用户和角色是多对多,有个中间表 auth_user_group
        -角色(组):auth_group
        	角色和权限多对多:auth_group_permission
        -权限:auth_permission
        
   -django为了更细粒度的做权限划分,又多加了个 
		用户和权限多对多
    	auth_user_permission

【1】数据准备

  • models.py
class Book(models.Model):
    username = models.CharField(max_length=32)
  • admin.py
# 这样在admin后台才能显示User表和Book表

from django.contrib import admin

# Register your models here.

from .models import User, Book

admin.site.register(User)
admin.site.register(Book)

  • serialzier.py
from .models import Book
class BookSerialzier(serializers.ModelSerializer):
    class Meta:
        model=Book
        fields='__all__'
  • views.py
from .models import  Book
from .serialzier import BookSerialzier
class BookView(APIView):


    def get(self,request):
        books=Book.objects.all().first()
        # <class 'rest_framework.serializers.ListSerializer'>
        # BookSerialzier
        serialzier=BookSerialzier(instance=books,many=True)
        print(type(serialzier))
        return Response('ok')
  • urls.py
from django.urls import path
from .views import BookView

urlpatterns = [
    path('books/', BookView.as_view()),
]
  • 前端展示

【2】修改app名字,表名字和表里的对象名字

(1)修改app名字

  • apps.py
from django.apps import AppConfig


class Aoo01Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'aoo01'
    verbose_name = '应用一'

(2)修改表名字

  • models.py
class Book(models.Model):
    username = models.CharField(max_length=32)
    class Meta:
        verbose_name='图书表'
        verbose_name_plural='图书表'

(3)修改表里的对象名字

  • models.py
class Book(models.Model):
    username = models.CharField(max_length=32)
    class Meta:
        verbose_name='图书表'
        verbose_name_plural='图书表'
    def __str__(self):
        return self.username

【3】添加不同权限分组

  • 再添加一个UserInfo的用户表
from django.contrib import admin

# Register your models here.

from .models import User, Book, UserInfo

admin.site.register(User)
admin.site.register(Book)
admin.site.register(UserInfo)
  • models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    mobile = models.CharField(max_length=11, default=True)
    class Meta:
        verbose_name='用户表'
        verbose_name_plural='用户表'
    def __str__(self):
        return self.username
  • 创建一个权限组

  • 将用户分配到权限组

  • 切换到oppo用户只有增加和查看权限

【4】单独给用户增加某个权限

切换到oppo用户有增加和查看权限还有新增的修改和删除功能

Ⅱ 补充

【一】锁定解锁用户接口

# 锁定解锁用户接口--->
	-前端传:用户id,lock:True,False
    -视图类继承谁?
    	-不用序列化:APIView
        -自动生成路由:ViewSetMixin
        -/api/v1/user/3/locked/-->post请求-->请求体{lock:True}  # 请求地址携带id
        -/api/v1/user/locked/-->post请求-->请求体{user_id:3,lock:True}  # 请求地址不携带id
        @action(methods=[POST],detail=True)
        def locked(self,request,pk)
        	user=根据pk拿到--》is_activite=True
            return Response()

【二】发送短信接口

# 发送短信
	-前端:get,mobile-->带在路径中
    -视图类继承谁?
    	-不用序列化:APIView
        -自动生成路由:ViewSetMixin
        @ction(methods=[POST],detail=False)
        def send_sms(self,request):
            mobile=requset.query_params.get('mobile')
            发送短信方法(mobile)
            return Response()

Ⅲ drf部分源码分析

【一】APIView源码

# 问题  继承APIView后
	-csrf认证没了
    -在执行视图类方法前执行三大认证
    -处理全局异常
    -包装了新的Request
    
    
    
# 入口
	-1 请求来了--->路由匹配成功-->会执行路由后配置的函数内存地址加括号,并且把request对象传入
    	path('demo01/', demo)-->demo(request)
        
    -2 path('user/', UserView.as_view())---》路由匹配成功就会执行 UserView.as_view()(request)--->最终执行的是:跟请求方式同名的方法
    
    -3 先看 UserView.as_view()-->去APIView中找 as_view()
    	3.1 @classmethod :类直接调用
        3.2 执行完的结果是:
        	# 执行了父类的as_view--->django的View的as_view-->执行结果是 as_view内部有个 view闭包函数
        	view = super().as_view(**initkwargs) # django的View的as_view内有个view闭包函数
            return csrf_exempt(view) # 去除csrf认证
        
  	-4 请求来了,本质执行的是 UserView.as_view()(requets)--->本质是:django的View的as_view内有个view闭包函数去除了csrf认证--->view(request)
        
    -5 读django的--->as_view-->view闭包函数
    	return self.dispatch(request, *args, **kwargs)
        
    6 本质是:self.dispatch(request, *args, **kwargs)--->APIView的dispatch
    7 整个逻辑由:APIView的dispatch决定
        def dispatch(self, request, *args, **kwargs):
            # 1 包装了新的Request
            request = self.initialize_request(request, *args, **kwargs)
            # 2 放到了视图类的对象中
            self.request = request
            try:
                # 3 三大认证,依次执行
                self.initial(request, *args, **kwargs)
                # 4 假设get请求-->request.method.lower()-->get字符串
                # http_method_names:列表,带了所有请求方式-->get在里面
                if request.method.lower() in self.http_method_names:
                    # 4.1 self 是 视图类的对象
                    # 去视图类对象中反射-->get方法
                    # handler 就是 视图类中跟请求方式同名的方法  内存地址
                    handler = getattr(self, request.method.lower(),
                                      self.http_method_not_allowed)
                else:
                    handler = self.http_method_not_allowed
                # 5 执行了 get(request)--->触发我们写的UserView中得get方法
                response = handler(request, *args, **kwargs)
            except Exception as exc:
                # 6 在执行三大认证或视图类的方法过程中,只要出了异常,都会执行handle_exception
                # 全局异常
                '''
                #1 去配置文件中,找到异常处理函数:
                exception_handler = self.get_exception_handler()
                # 2 执行异常处理函数
                response = exception_handler(exc, context)
                '''
                response = self.handle_exception(exc)
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response
        
        
        
# 补充,装饰器用法
	#正统写法--->本质是--->被装饰函数=装饰器(被装饰的函数)
	@装饰器
    def 被装饰的函数():
        pass
    # 不正统写法
    被装饰函数=装饰器(被装饰的函数)	
    view=csrf_exempt(view)
    return view     # 两种效果 其实都一样

【二】新的Request对象

# 问题:
	-request.data 为什么有       # 看完了
    -request._request  就是老的  # 看完了
    -request.query_params       #  看完了
    -用新的,跟老的一样用  


# 1 入口:APIView---dispatch--->request = self.initialize_request(request, *args, **kwargs)
# 2 传入了老的reuqest对象
	# 传入的request 是老的
    def initialize_request(self, request, *args, **kwargs):
        # 返回了新的
        return Request(
            request, #老的
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
# 3 Request 类的__init__
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        self._request = request # 把老的request放到新的request._request中了
        
# 4 request.query_params    
	@property
    def query_params(self):
        return self._request.GET
    
    
    
# 5 request.data 为什么有--->把所有编码格式的请求体数据,都放在了self._full_data中了-->相当于使用了缓存--->一旦执行过一次
	@property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files() # 把所有编码格式的请求体数据
        return self._full_data
    
    
    
    
    
# 6 用新的,跟老的一样用 
	request.method--->新的里面没有这个属性--->就会触发---—>__getattr__执行
    def __getattr__(self, attr):
        try:
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)



# 补充:对象的 . 拦截
	对象.属性/ 方法,调用--->如果存在,直接就用到了,如果不存在--->就会保存
    
    通过重写 __getattr__, 做 . 拦截--->如果不存在,会执行__getattr__
    
    对象.属性--——>如果属性不存在,会触发  __getattr__执行

【三】序列化类之 many=True 作用

# 1 它俩不是同一个对象--->下面两个应该都是 BookSerialzier的对象
serialzier=BookSerialzier(instance=books,many=True)
serialzier=BookSerialzier(instance=book) 

# 2 serialzier=BookSerialzier(instance=books,many=True) 是ListSerializer的对象

# 3 serialzier=BookSerialzier(instance=book) 是BookSerialzier的对象


# 4 谁控制对象的生成 --->>>类()--->>先执行__new__创建一个空对象---->>再执行__inti__
	-当执行到 __init__的时候,起始对象已经创建出来了
    -在它执行,其实先执行了 __new__
    
# 5 通过重写 __new__控制类的生成

# 6 如果加了many=True--->会执行__new__--->改变对象的生成
serialzier=BookSerialzier(instance=books,many=True)--->执行__new__--->
    def __new__(cls, *args, **kwargs):
        if kwargs.pop('many', False): # 有many=True
            '''
            list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
            return list_serializer_class(*args, **list_kwargs)
            '''
            return cls.many_init(*args, **kwargs)
        return super().__new__(cls, *args, **kwargs) # 没有many=True-->就是BookSerializer对象
    
    
# 7 ListSerializer本质--->[BookSerializer对象1,BookSerializer对象2,BookSerializer对象3]

posted on 2024-08-05 23:35  silence^  阅读(5)  评论(0编辑  收藏  举报

导航