Restful framework【第六篇】认证组件
发布日期:2025-01-03 18:37 点击次数:105
基本用法
简单实例
settings
先创建一个project和一个app(我这里命名为API)
首先要在settings的app中添加
url
models
一个保存用户的信息
一个保存用户登录成功后的token
views
用户登录(返回token并保存到数据库)
利用postman发请求
如果用户名和密码正确的话 会生成token值,下次该用户再登录时,token的值就会更新
数据库中可以看到token的值
当用户名或密码错误时,抛出异常
添加认证
基于上面的例子,添加一个认证的类
url
views
用postman发get请求
请求的时候没有带token,可以看到会显示“用户认证失败”
这样就达到了认证的效果,django-rest-framework的认证是怎么实现的呢,下面基于这个例子来剖析drf的源码。
drf的认证源码分析
源码流程图
请求先到dispatch
dispatch()主要做了两件事
封装request
认证
具体看我写的代码里面的注释
reuqest
(1)initialize_request()
可以看到initialize()就是封装原始request
(2)get_authenticators()
通过列表生成式,返回对象的列表
(3)authentication_classes
APIView里面有个 authentication_classes 字段
可以看到默认是去全局的配置文件找(api_settings)
认证
self.initial(request, *args, **kwargs)
(1)initial()
主要看 self.perform_authentication(request),实现认证
(2)perform_authentication()
调用了request.user
(3)user
request.user的request的位置
点进去可以看到Request有个user方法,加 @property 表示调用user方法的时候不需要加括号“user()”,可以直接调用:request.user
(4)_authenticate()
循环所有authenticator对象
返回值就是例子中的:
token_obj.user-->>request.user
token_obj-->>request.auth
当都没有返回值,就执行self._not_authenticated(),相当于匿名用户,没有通过认证
面向对象知识:
子类继承 父类,调用方法的时候:
优先去自己里面找有没有这个方法,有就执行自己的
只有当自己里面没有这个方法的时候才会去父类找
因为authenticate方法我们自己写,所以当执行authenticate()的时候就是执行我们自己写的认证
父类中的authenticate方法
我们自己写的
认证的流程就是上面写的,弄懂了原理,再写代码就更容易理解为什么了。
配置文件
继续解读源码
默认是去全局配置文件中找,所以我们应该在settings.py中配置好路径
api_settings源码
setting中‘REST_FRAMEWORK’中找
全局配置方法:
API文件夹下面新建文件夹utils,再新建auth.py文件,里面写上认证的类
settings.py
auth.py
在settings里面设置的全局认证,所有业务都需要经过认证,如果想让某个不需要认证,只需要在其中添加下面的代码:
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from API import models
from rest_framework.request import Request
from rest_framework import exceptions
from rest_framework.authentication import BasicAuthentication
ORDER_DICT = {
1:{
'name':'apple',
'price':15
},
2:{
'name':'dog',
'price':100
}
}
def md5(user):
import hashlib
import time
#当前时间,相当于生成一个随机的字符串
ctime = str(time.time())
m = hashlib.md5(bytes(user,encoding='utf-8'))
m.update(bytes(ctime,encoding='utf-8'))
return m.hexdigest()
class AuthView(APIView):
'''用于用户登录验证'''
authentication_classes = [] #里面为空,代表不需要认证
def post(self,request,*args,**kwargs):
ret = {'code':1000,'msg':None}
try:
user = request._request.POST.get('username')
pwd = request._request.POST.get('password')
obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
if not obj:
ret['code'] = 1001
ret['msg'] = '用户名或密码错误'
#为用户创建token
token = md5(user)
#存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
ret['token'] = token
except Exception as e:
ret['code'] = 1002
ret['msg'] = '请求异常'
return JsonResponse(ret)
class OrderView(APIView):
'''订单相关业务'''
def get(self,request,*args,**kwargs):
# self.dispatch
#request.user
#request.auth
ret = {'code':1000,'msg':None,'data':None}
try:
ret['data'] = ORDER_DICT
except Exception as e:
pass
return JsonResponse(ret)
API/view.py代码
再测试一下我们的代码
不带token发请求
带token发请求
drf的内置认证
rest_framework里面内置了一些认证,我们自己写的认证类都要继承内置认证类 "BaseAuthentication"
BaseAuthentication源码:
修改自己写的认证类
自己写的Authentication必须继承内置认证类BaseAuthentication
其它内置认证类
rest_framework里面还内置了其它认证类,我们主要用到的就是BaseAuthentication,剩下的很少用到
总结
只要用了drf,post提交数据,就不需要csrf验证了,源码里对View用了禁用csrf
自己写认证类方法梳理
(1)创建认证类
继承BaseAuthentication --->>1.重写authenticate方法;2.authenticate_header方法直接写pass就可以(这个方法必须写)
(2)authenticate()返回值(三种)
None ----->>>当前认证不管,等下一个认证来执行
raise exceptions.AuthenticationFailed('用户认证失败') # from rest_framework import exceptions
有返回值元祖形式:(元素1,元素2) #元素1复制给request.user; 元素2复制给request.auth
(3)局部使用
authentication_classes = [BaseAuthentication,]
(4)全局使用
源码流程
--->>dispatch
--封装request
---获取定义的认证类(全局/局部),通过列表生成式创建对象
---initial
----peform_authentication
-----request.user (每部循环创建的对象)