rest_framework权限组件、频率、3组件总结
https://www.cnblogs.com/yuanchenqi/articles/8719520.html
https://www.cnblogs.com/alice-bj/p/9252207.html#_label3
1、权限组件
1. 源码
1.权限函数



2.API settings配置

3.核心代码
View下的 self,代表view
‘message’ 为认证错误返回的信息

3. 需求:不是vip,不能看author
user表

数据库迁移与生成

我要知道这次的请求人是谁
在auth认证组件中中里面有 user
权限用到认证中的信息

utils

view
utils里的 类 和 view里的实例对象,必须一致

test
通过了第一层的认证,没有通过第二次的权限


切换超级用户登录


4. 全局配置
通过权限认证 true
没有通过 false

test
任何页面都需要权限才能访问


5. Code与Question
Question1
books 先auth一下,才有request.name
不然都是,

Question 2
auth的全局配置会影响login页面


code
models
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)
type_choices = ((1,"普通用户"),(2,'SVip'),(3,'SSVip'))
user_type = models.IntegerField(choices=type_choices,default=1)
views
# Author
from .models import Author
from app01.serilizer import AuthorModelSerializers
from rest_framework import viewsets
from app01.utils import SVipPermission
class AuthorView(viewsets.ModelViewSet):
# authentication_classes = [TokenAuth] # 加上这个,走自己的认证,也就是不认证
# 不加的话,自己没有,走全局的认证
permission_classes = [SVipPermission,]
# list数据 # create数据 # 继承APIView
queryset = Author.objects.all() # queryset,serilizers 名称不能修改
serializer_class = AuthorModelSerializers
utils
from .models import User
class SVipPermission(object):
message = "只有超级用户才能访问"
def has_permission(self,request,view):
username = request.user
print(username)
user_type = User.objects.filter(name=username).first().user_type # 对象直接 . 自己的属性
if user_type == 3:
return True # 通过权限认证,可以看author表
else:
return False
settings
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'],
# 'DEFAULT_PERMISSION_CLASSES':['app01.utils.SVipPermission']
}
2. 频率组件
1、核心代码



2. 要求访问站点的频率不能超过每分钟20次
ip time


3.request里面有什么内容
请求头
客户端的ip
通过什么都不做
不拖过才返回错误信息


请求头必会的
refer
useraget
contentype
4. 全局配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'],
'DEFAULT_PERMISSION_CLASSES':['app01.utils.SVipPermission'],
'DEFAULT_THROTTLE_CLASSES':['app01.utils.VisitRateThrottle'],
'DEFAULT_THROTTLE_RATES':{
'visit_rate':'1/m'
}
}
5.局部配置
utils
from rest_framework.throttling import BaseThrottle
VISIT_RECORD={}
class VisitThrottle(BaseThrottle):
def __init__(self):
self.history=None
def allow_request(self,request,view):
remote_addr = request.META.get('REMOTE_ADDR')
print(remote_addr)
import time
ctime=time.time()
if remote_addr not in VISIT_RECORD:
VISIT_RECORD[remote_addr]=[ctime,]
return True
history=VISIT_RECORD.get(remote_addr)
self.history=history
while history and history[-1]<ctime-60:
history.pop()
if len(history)<3:
history.insert(0,ctime)
return True
else:
return False
def wait(self):
import time
ctime=time.time()
return 60-(ctime-self.history[-1])
view
from app01.service.throttles import *
class BookViewSet(generics.ListCreateAPIView):
throttle_classes = [VisitThrottle,]
queryset = Book.objects.all()
serializer_class = BookSerializers
3. 三大组件总结
1.笔记
3 def dispatch():
#一 初始化操作
# (1) 构建新的request:
self.request=self.initial_request()
# self.request._request
# self.request.GET
# self.request.data
# (2) 执行组件
# 认证,权限,频率
# 认证:request.user
self.initial(request, *args, **kwargs)
==== # 认证组件
self.perform_authentication(request)
==== request.user
=====
for authenticator in self.authenticators: # [TokenAuth(),]
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
# 权限组件
self.check_permissions(request)
===========
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
# 频率组件
self.check_throttles(request)
=============
for throttle in self.get_throttles(): # [VisitRateThrottle(),]
if not throttle.allow_request(request, self):
self.throttled(request, throttle.wait()) # 受限制
# 分发
if request.method.lower() in self.http_method_names:
handler = getattr(self,request.method.lower(),
self.http_method_not_allowed)
response = handler(request, *args, **kwargs)
return response
2.代码
urls
"""restdemo URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from django.urls import re_path # 正则表达式的 from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('publishes/', views.PublishView.as_view()), # view(request)====> APIView:dispatch() re_path(r'publishes/(?P<pk>\d+)/$', views.PublishDetailView.as_view(),name="detailPublish"), path('books/', views.BookView.as_view()), re_path(r'books/(\d+)/$', views.BookDetailView.as_view()), # path('authors/', views.AuthorView.as_view()), # re_path(r'authors/(?P<pk>\d+)/$', views.AuthorDetailView.as_view()), path('authors/', views.AuthorView.as_view({"get":"list","post":"create"}),name="book_list"), re_path(r'authors/(?P<pk>\d+)/$', views.AuthorView.as_view({ "get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy" }),name="book_detail"), path('login/',views.LoginView.as_view()) ]
models
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) type_choices = ((1,"普通用户"),(2,'SVip'),(3,'SSVip')) user_type = models.IntegerField(choices=type_choices,default=1) class Token(models.Model): user = models.OneToOneField("user",on_delete=models.CASCADE) token = models.CharField(max_length=128) def __str__(self): return self.token class Book(models.Model): title=models.CharField(max_length=32) price=models.IntegerField() pub_date=models.DateField() publish=models.ForeignKey("Publish",on_delete=models.CASCADE) authors=models.ManyToManyField("Author") def __str__(self): return self.title class Publish(models.Model): name=models.CharField(max_length=32) email=models.EmailField() def __str__(self): # return self.name return self.email class Author(models.Model): name=models.CharField(max_length=32) age=models.IntegerField() def __str__(self): return self.name
views
from django.shortcuts import render,HttpResponse from rest_framework.views import APIView from rest_framework.response import Response from app01.serilizer import BookModelSerializers # 从serilizer中导入 from app01.serilizer import PublishModelSerializers from .models import Book,Publish class PublishView(APIView): # APIView def get(self,request): publish_list = Publish.objects.all() ps = PublishModelSerializers(publish_list,many=True) return Response(ps.data) def post(self,request): ps = PublishModelSerializers(data=request.data) if ps.is_valid(): ps.save() return Response(ps.data) else: return Response(ps.errors) class PublishDetailView(APIView): def get(self,request,pk): # 获取某publish的信息 publish = Publish.objects.filter(pk=pk).first() ps = PublishModelSerializers(publish) return Response(ps.data) def put(self,request,pk): # 更新某pub的信息 publish = Publish.objects.filter(pk=pk).first() ps = PublishModelSerializers(publish,data=request.data) if ps.is_valid(): ps.save() return Response(ps.data) else: return Response(ps.errors) def delete(self,request,pk): # 删除某天publish Publish.objects.filter(pk=pk).delete() return Response("Delete 第%s个出版社"%(pk)) from app01.utils import TokenAuth class BookView(APIView): authentication_classes = [TokenAuth,] # 认证组件 # permission_classes =[] # 权限组件 # throttle_classes = [] # 频率组件 def get(self,request): print("request_user",request.user) print("request_auth",request.auth) book_list = Book.objects.all() bs = BookModelSerializers(book_list,many=True,context={'request':request}) return Response(bs.data) # Response继承HttpResponse def post(self,request): # post请求的数据 bs = BookModelSerializers(data=request.data,context={'request':request}) if bs.is_valid(): print(bs.validated_data) bs.save() # create方法 return Response(bs.data) else: return Response(bs.errors) class BookDetailView(APIView): def get(self,request,id): # 获取某本书的信息 book = Book.objects.filter(pk=id).first() # 过滤单挑data bs = BookModelSerializers(book,context={'request':request}) return Response(bs.data) def put(self,request,id): # 更新某本书的字段 book = Book.objects.filter(pk=id).first() bs = BookModelSerializers(book,data=request.data,context={'request':request}) if bs.is_valid(): bs.save() # 实质create方法 return Response(bs.data) else: return Response(bs.errors) def delete(self,request,id): # 删除某条数据 Book.objects.filter(pk=id).delete() return Response("Delete 第%s本书成功"%(id)) # Author # 方法3:ModelViewSet from .models import Author from app01.serilizer import AuthorModelSerializers from rest_framework import viewsets from app01.utils import SVipPermission # from app01.utils import VisitRateThrottle class AuthorView(viewsets.ModelViewSet): # authentication_classes = [TokenAuth] # 加上这个,走自己的认证,也就是不认证 # 不加的话,自己没有,走全局的认证 # permission_classes = [SVipPermission,] # throttle_classes = [VisitRateThrottle,] # list数据 # create数据 # 继承APIView queryset = Author.objects.all() # queryset,serilizers 名称不能修改 serializer_class = AuthorModelSerializers from .models import User,Token import json class LoginView(APIView): def get(self,request): return Response('login........') def post(self,request): print(1111) name = request.data.get('name') pwd = request.data.get('pwd') user = User.objects.filter(name=name,pwd=pwd).first() res = {'state_code':1000,'msg':None} if user: random_str = get_random_str(user.name) Token.objects.update_or_create(user=user,defaults={"token":random_str}) res['token'] = random_str else: res['state_code'] = 1001 # 错误状态码 res['msg'] = "用户名或者密码错误" return Response(json.dumps(res,ensure_ascii=False)) # 中文转义 import hashlib import time def get_random_str(user): """md5加密""" ctime = str(time.time()) md5 = hashlib.md5(bytes(user,encoding='utf8')) # user加盐 md5.update(bytes(ctime,encoding='utf8')) return md5.hexdigest()
utils
from .models import User class SVipPermission(object): message = "只有超级用户才能访问" def has_permission(self,request,view): username = request.user print(username) user_type = User.objects.filter(name=username).first().user_type # 对象直接 . 自己的属性 if user_type == 3: return True # 通过权限认证,可以看author表 else: return False # 全局登录认证 from .models import Token from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication class TokenAuth(BaseAuthentication): def authenticate(self,request): token = request.GET.get("token") token_obj = Token.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed("验证失败") return (token_obj.user.name,token_obj.token) def authenticate_header(self,request): # 暂时不用管 pass ''' class VisitRateThrottle(object): def allow_request(self,request,view): # 要求访问站点的频率不能够超过每分钟20次 if 1: print(request.META.get("REMOTE_ADDR")) return True else: return False from rest_framework.throttling import BaseThrottle VISIT_RECORD={} class VisitThrottle(BaseThrottle): def __init__(self): self.history=None def allow_request(self,request,view): remote_addr = request.META.get('REMOTE_ADDR') print(remote_addr) import time ctime=time.time() if remote_addr not in VISIT_RECORD: VISIT_RECORD[remote_addr]=[ctime,] return True history=VISIT_RECORD.get(remote_addr) self.history=history while history and history[-1]<ctime-60: history.pop() if len(history)<3: history.insert(0,ctime) return True else: return False def wait(self): import time ctime=time.time() return 60-(ctime-self.history[-1]) '''
settings
STATIC_URL = '/static/' REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.TokenAuth'], 'DEFAULT_PERMISSION_CLASSES':['app01.utils.SVipPermission'], 'DEFAULT_THROTTLE_CLASSES':['app01.utils.VisitRateThrottle'], 'DEFAULT_THROTTLE_RATES':{ 'visit_rate':'1/m' } }

浙公网安备 33010602011771号