认证:
首先
导入rest_framework.views中的 APIView方法
from rest_framework.views import APIView
我们来看一段伪代码,MyClassView继承了APIView就有了APIView的功能
class APIView(View):
pass
class MyClassView(APIView):
pass
在class类里面的(APIView)在pycharm按住ctrl点击APIView,就会跳到这个方法里面 "例如最后面的大写字母,“DEFAULT_AUTHENTICATION_CLASSES"就是各个组件的配置名”
我们开始进入认证的操作流程:
首先在model中创建两个模型
from django.db import models
# Create your models here.
class UserInfo(models.Model):
"""用户表"""
user_type_choices = (
(1, "普通用户"),
(2, "VIP"),
(3, "SVIP")
)
user_type = models.IntegerField(choices=user_type_choices)
username = models.CharField(max_length=32, unique=True)
password = models.CharField(max_length=64)
class UserToken(models.Model):
"""token表"""
user = models.OneToOneField(to="UserInfo")
token = models.CharField(max_length=64)
一个是用户表 一个是token表 用户表中加入了用户类型 token表关联用户表 成一对一的类型 所以一个用户只能有一个token
然后我们开始写view视图 首先我们要创建token生成加密字符
#创建md5函数 继承token模型的user对象
def md5(user):
#导入哈希加密
import hashlib
#导入时间
import time
#变量名ctime 接收现在的时间转为字符str类型
ctime = str(time.time())
#将user对象转为字节并用哈希md5加密 变为16进制字符
m = hashlib.md5(bytes(user, encoding="utf-8"))
#修改并加入时间戳
m.update(bytes(ctime, encoding="utf-8"))
#并返回
return m.hexdigest()
另一种写法
import hashlib
import time
#创建token
def createToken(user):
md5 = hashlib.md5()
#修改账户名字节并加入时间戳 和utf-8(时间戳)
md5.update(bytes(user + str(time.time()), encoding='utf-8'))
#返回摘要,作为十六进制数据字符串值
token = md5.hexdigest()
#返回给token
return token
然后设置登录功能:
#设置登录类
class AuthView(APIView):
# 提交我们用 内置源码的post请求
def post(self,request,*args,**kwargs):
# 设置状态码
ret = {"state_code": 1000, "msg": None}
#判断异常
try:
#原生_request改写request方法 获取前端表单里面的用户名
username = request._request.POST.get("username")
#获取前端表单里面的密码
password = request._request.POST.get("password")
# 用变量名obj 接收数据库里的信息并进行 前端表单与数据库的匹配
obj = models.UserInfo.object.filter(username=username,password=password).first()
#然后进行判断 如果匹配的内容不对
if not obj:
# 就发送状态码 1001
ret["state_code"] = 1001
# 用户名或者 密码错误
ret["msg"] = "用户名或者密码错误"
# 否则为登陆用户创建一个token
token = md5(username)
# 存到数据库 存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=obj, defaults={"token": token})
# 发送状态码
ret["token"] = token
#告知请求成功
ret["msg"] = "请求成功"
#判断异常
except Exception as e:
# 发送状态码
ret["state_code"] = 1002
# 请求异常
ret["msg"] = "请求异常"
#返回JsonResponse
return JsonResponse(ret)
这时我们在 Django项目 我的应用中myapp就是我的应用里面创建 我的工具包 myutils 里面去创建各种组件的方法 这样看着明显而且 省地方! 随后我们创建auth.py来写我们的 认证组件方法:
然后进入 auth.py 导入rest_framework.authentication里面的BaseAuthentication方法,导入应用中的模型类,导入判断不包括在内的方法
from rest_framework.authentication import BaseAuthentication
from myapp import models
from rest_framework import exceptions
#创建一个我的认证类 继承BaseAuthentication方法
class MyAuthtication(BaseAuthentication):
# 设置内置authenticate重写authenticate这个方法
def authenticate(self, request):
# 将用户输入的token用变量接收
token = request._request.GET.get("token")
# 然后在数据库进行匹配
token_obj = models.UserToken.objects.filter(token=token).first()
# 如果认证失败
if not token_obj:
#就返回失败
raise exceptions.AuthenticationFailed("用户认证失败")
# 在 rest framework内部 会将这两个字段赋值给request,以供后续操作使用
#正确就返回用户和token
return (token_obj.user, token)
# 如果pass 就调用原有的方法
class MyAuthtication_None(BaseAuthentication):
def authenticate(self, request):
pass
另一种方法
#创建 我的Authtication
class MyAuthtication(BaseAuthentication):
#使用authenticate方法
def authenticate(self, request):
#获取token
token = request._request.GET.get('token')
#进行判断 如果不是token
if not token:
#返回元组验证失败
raise AuthenticationFailed('未登录')
#否则
else:
#在数据库UserToken表中进行比对 从第一个开始
usertoken = UserToken.objects.filter(token=token).first()
#如果是usertoken
if usertoken:
#就返回用户的token
return (usertoken.user, token)
#否则验证失败
else:
raise AuthenticationFailed('验证失败')
然后我们在settings设置全局配置
在class类里面的(APIView)在pycharm按住ctrl点击APIView,就会跳到这个方法里面 "例如最后面的大写字母,“DEFAULT_AUTHENTICATION_CLASSES"就是各个组件的配置名”
然后我们在settings设置全局配置
在class类里面的(APIView)在pycharm按住ctrl点击APIView,就会跳到这个方法里面 "例如最后面的大写字母,“DEFAULT_AUTHENTICATION_CLASSES"就是各个组件的配置名”
将"DEFAULT_AUTHENTICATION_CLASSES":[设置类的路径]
然后就可以在view视图中加入
authentication_classes = []
如果不在settings配置全局设置 就要单独写这个进行验证 所以 我们要先在view中导入
from myapp.myutils.throttle import MyAuthtication
#将登录类里写入 进行认证
authentication_classes = [MyAuthtication]
就像这样
然后我们试着 在postman 软件中 输入用户名及密码 申请登录尝试我们的代码使用是否正确
输入我们在urls.py中设置的接口 也就是路由
from django.contrib import admin
from myapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/v1/auth/$', views.AuthView.as_view()),
]
然后输入到postman 中 点击body 中的 X-www-form-urlencoded 输入 用户名 密码进行 登录匹配
登录成功
登录失败
然后我们去看authenticate这个的源码
def authenticate(self, request):
token = request._request.GET.get("token")
首先点击
在class类里面的(APIView)在pycharm按住ctrl点击APIView,然后向下翻找到 def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
#进这里 #点击这个
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
找到def dispatch(self, request, *args, **kwargs):中的 self.initial并点击
try:
#进这里 #点击这个
self.initial(request, *args, **kwargs)
然后将会看到:
# 代表 认证组件
self.perform_authentication(request)
# 代表 权限组件
self.check_permissions(request)
# 代表 限流组件
self.check_throttles(request)
然后 点击self.perform_authentication(request)这个方法
在这里它封装了 request.user方法 点击request.user然后选择第三个
在这里封装了self._authenticate() 点击self._authenticate()
rest framework的第二组件
权限:
首先 观察我们之前创建的 用户表 用户分为三种类型 三种类型 就代表在登录 验证 或者订单中来实现 这三种权限显示的内容
我们先在view.py视图中 写好一个订单表 方便在写权限代码时 用权限功能 来使用 订单表 如何用权限显示订单内容
# 创建一个ORDER_DICT字典 输入一些信息
ORDER_DICT = {
1: {
"name": "张三",
"age": 18,
"gender": "男",
"orders": [{
"name": "娃娃",
"price": 1000
}]
},
2: {
"name": "李四",
"age": 20,
"gender": "女",
"orders": [{
"name": "你猜",
"price": 1200
}]
},
}
# 创建OrderView类 继承APIView
class OrderView(APIView):
"""
订单相关业务
"""
# 设置get请求
def get(self, request, *args, **kwargs):
# 状态码
ret = {"state_code": 1000, "msg": None, "data": None}
# 判断异常
try:
# 如果正确 就返回字典的数据
ret['data'] = ORDER_DICT
# 错误就返回状态码
except Exception as e:
pass
return JsonResponse(ret)
然后配置路由urls.py进行配置
from django.conf.urls import url
from django.contrib import admin
from myapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 认证接口
url(r'^api/v1/auth/$', views.AuthView.as_view()),
# 订单接口
url(r'^api/v1/order/$', views.OrderView.as_view()),
]
在myapp应用中的工具包myutlis中创建permission.py代表权限组件的配置
# 在rest_framework.permissions 导入BasePermission方法
from rest_framework.permissions import BasePermission
# 创建SVIPPermission类 继承BasePermission方法
class SVIPPermission(BasePermission):
# 状态码
message = "无权访问"
# 重写 has_permission方法
def has_permission(self, request, view):
# 如果 用户 user_type 类型 不等于3
if request.user.user_type != 3:
# 就无法访问
return False
# 否则可以访问
return True
这个 def has_permission(self, request, view):方法从哪来? 我们要看里面的源码:
首先点击 self.dispatch() 找到 self.initial(request,args,*kwargs)点击 进入
然后点击 代表权限的组件方法
这里会出现 点击这个选择第三个 会出现我们冲的的方法
随后滚动鼠标 会出现这个方法
百度翻译一下
“”"
Allows access only to admin users.
“”"
意思是 仅允许管理员用户访问 所以改写这个方法
随后在views.py里面去配置 订单的权限及认证的组件配置
# 导入的这个负责 认证
# 在 我的应用中从 我的组件包中的 auth 导入MyAuthtication类
from myapp.myutils.auth import MyAuthtication
# 导入的这个负责 权限
# 在 我的应用中从 我的组件包中的 permission 导入SVIPPermission类
from myapp.myutils.permission import SVIPPermission
然后 加入这个 就会加入组件包 来实现 认证 权限两个功能
或者我们在settings.py设置全局组件配置 权限 首先我们要找到源码来写入 这个配置的功能
在class类里面的(APIView)在pycharm按住ctrl点击APIView,然后向下翻找到
DEFAULT_PERMISSION_CLASSES 这个就代表配置 settings.py需要设置的方法 [这里写的是方法类的路径]
然后在view.py订单视图中 写入
class OrderView(APIView):
"""
订单相关业务
"""
authentication_classes = []
permission_classes = []
然后我们用postman进行 实际测试验证
先找到数据库表中 user_type类型为svip的 因为如果是1或者2类型就无法访问
然后进行登录获取token
将获取到的token放在一个文本里 然后在重新打开一个postman的页面 打开配置的路由找到路径 复制这个路径
将这个链接 粘贴到postman 新页面?token=你的文本里面的token
http://127.0.0.1:8000/api/v1/order/?token= 后面放你从文本复制的token
在postman进行验证 输入对的token 就可以获取到表单
输入错误token再次尝试 用户认证失败
在数据库找一个 user_type类型为2 的进行登录 获取token 进行获取订单看看是什么结果
将token输入告诉 无权限访问 那么功能都可以实现
################################################################
rest framework的第三组件
限流:
限流就是限制访问频率或者次数
首先 在我的应用组件包创建限流 throttle.py文件 在里面设置我们的限流方法
# 从rest_framework.throttling 导入BaseThrottle方法
from rest_framework.throttling import BaseThrottle
# 导入时间
import time
# 设置一个空字典
HISTORY_DICT = {}
# 写MyThrottle类继承 BaseThrottle方法
class MyThrottle(BaseThrottle):
# 初始化self.history
def __init__(self):
self.history = None
# 重写allow_request方法
def allow_request(self, request, view):
# 获取 (META["REMOTE_ADDR"])当前用户的ip
ip_addr = request._request.META["REMOTE_ADDR"]
# 获取当前时间
ctime = time.time()
# 如果 用户当前的ip 不在空字典中
if ip_addr not in HISTORY_DICT:
# 那么就把当前ip赋予一个 现在的时间
HISTORY_DICT[ip_addr] = [ctime, ]
return True
# 如果这条ip在空字典中
history = HISTORY_DICT[ip_addr]
# 初始化的self.history
self.history = history
# 在空字典的ip 找到最后一个ip 是最早的时间那个 小于现在时间的60秒
while history and history[-1] < ctime - 60:
# 就删除最后一个
history.pop()
# 如果ip记录 小于3次
if len(history) < 3:
# 就添加ip 并赋予现在的时间
history.insert(0, ctime)
return True
# 如果访问返回True表示可以继续往下走,False被限制访问
return False
def wait(self):
# 这里是应该返回 剩余的 等待时间
# 要先拿到历史记录
# 当前时间
ctime = time.time()
return 60 - (ctime - self.history[-1])
我们重写了def allow_request(self, request, view):方法 我们可以看看源码是怎样写的
首先点击 self.dispatch() 找到 self.initial(request,args,*kwargs)点击 进入
然后点击 代表限流的组件方法
在这里会找到封装的allow_request 点击它 选择第三个
这里就会出现allow_request源码的方法 和 wait源码的方法
我们开始在views.py设置 一个类来测试我们书写的代码逻辑是否正确
# 在我的组件包导入 MyThrottle方法
from myapp.myutils.throttle import MyThrottle
class StudentView(APIView):
authentication_classes = [MyAuthtication]
permission_classes = [SVIPPermission]
# 开启这个代表自己设置的限流
throttle_classes = [MyThrottle]
def get(self, request, *args, **kwargs):
# 获取当前的ip
ip = request.META.get('REMOTE_ADDR')
# 并返回当前的ip
return JsonResponse({'ip': ip})