四、Drf认证组件
4.1 快速使用
from django.shortcuts import render,HttpResponse
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
# Create your views here.
class Myauthentication(BaseAuthentication):
"""
用户认证:
1、读取请求传递过来的token
2、校验合法性
3、返回值
--3.1返回元组,如(11,22),认证成功,request.user=11,request.auth=22
--3.2抛出异常,认证失败,返回错误信息
--3.3返回None,多个认证类[类1,类2,类3,类4..。。]-->匿名用户
"""
def authenticate(self, request):
#获取token
token=request.GET.get('token')
if token:
#如果token校验成功,则返回一个元组(用户名和token),request.user=元组[0],request.auth=元组[1]
return 'sally',token
#如果校验失败则抛出异常
raise AuthenticationFailed({'code':2000,'error':'认证失败'})
class LoginView(APIView):
#该视图无需认证
authentication_classes = []
def get(self,request):
#user和auth都为None
print('user', request.user)
print('auth', request.auth)
return Response('login')
class UserView(APIView):
#该视图要需认证
authentication_classes = [Myauthentication,]
def get(self, request):
#user和auth为认证类Myauthentication返回的结果
print('user',request.user)
print('auth',request.auth)
return Response('user')
class OrderView(APIView):
#该视图要需认证
authentication_classes = [Myauthentication, ]
def get(self, request):
#user和auth为认证类Myauthentication返回的结果
print(request.user)
print(request.auth)
return Response('order')
认证的全局配置:
上个示例中,需要在每个视图中应用认证类,比较麻烦。
可以在settings.py中做全局配置
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER": None,
#这里指定一个或多个认证类(注意:认证类不能放在views合局视图文件中,不然会引发循环调用,这里将认证类放在了ext/auth文件中)
"DEFAULT_AUTHENTICATION_CLASSES":["ext.auth.Myauthentication",]
}
这样,默认所有视图都需要认证,如果某些视图不需要认证,只需要在这些视图函数中加入‘authentication_classes = []’即可。
class LoginView(APIView):
#不需要认证
authentication_classes = []
def get(self,request):
print('user', request.user)
print('auth', request.auth)
return Response('login')
class UserView(APIView):
# 需要认证
def get(self, request):
print('user',request.user)
print('auth',request.auth)
return Response('user')
class OrderView(APIView):
# 需要认证
def get(self, request):
print(request.user)
print(request.auth)
return Response('order')
4.2多个认证类
settings.py
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER": None,
"DEFAULT_AUTHENTICATION_CLASSES":["ext.auth.Myauthentication1",
"ext.auth.Myauthentication2",
"ext.auth.Noauthentication",]
}
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class Myauthentication1(BaseAuthentication):
"""
用户认证:
1、读取请求传递过来的token
2、校验合法性
3、返回值
--3.1返回元组,如(11,22),认证成功,request.user=11,request.auth=22
--3.2抛出异常,认证失败,返回错误信息
--3.3返回None,多个认证类[类1,类2,类3,类4..。。]-->匿名用户
"""
def authenticate(self, request):
token=request.GET.get('token')
if token=='123':
#如果验证成功,则返回用户名和token,不再执行下一个认证类
print(token)
return 'sally',token
#如果验证失败,则返回None,如果返回None则会执行下一个认证类
return None
class Myauthentication2(BaseAuthentication):
"""
用户认证:
1、读取请求传递过来的token
2、校验合法性
3、返回值
--3.1返回元组,如(11,22),认证成功,request.user=11,request.auth=22
--3.2抛出异常,认证失败,返回错误信息
--3.3返回None,多个认证类[类1,类2,类3,类4..。。]-->匿名用户
"""
def authenticate(self, request):
token = request.GET.get('token')
if token == '456':
#如果验证成功,则返回用户名和token,不再执行下一个认证类
print(token)
return 'ying',token
#如果验证失败,则返回None,如果返回None则会执行下一个认证类
return
class Noauthentication(BaseAuthentication):
"""
用户认证:
1、读取请求传递过来的token
2、校验合法性
3、返回值
--3.1返回元组,如(11,22),认证成功,request.user=11,request.auth=22
--3.2抛出异常,认证失败,返回错误信息
--3.3返回None,多个认证类[类1,类2,类3,类4..。。]-->匿名用户
"""
def authenticate(self, request):
print('认证失败')
#如果以上的认证类认证全部失败,则抛出错误,认证失败。
raise AuthenticationFailed({'code':2000,'error':'认证失败'})
4.3认证状态码
class Myauthentication1(BaseAuthentication):
def authenticate(self, request):
token=request.GET.get('token')
if token=='123':
print(token)
return 'sally',token
return None
def authenticate_header(self, request):
#修改认证状态码
return "API"
效果:
4.4子类约束
class Foo(object):
def f1(self):
#父类的函数中加上一个raise
raise NotImplementedError
class New(Foo):
def f2(self):
#如果子类定义了一个父类中不存在的方法,则会报错
print('f1')
obj=New()
Traceback (most recent call last):
File "G:\py_project\api\app_api\tests.py", line 70, in <module>
obj.f1()
File "G:\py_project\api\app_api\tests.py", line 61, in f1
raise NotImplementedError
NotImplementedError
4.5示例:用户登入和查看用户信息
4.5.1创建用户表
class User(models.Model):
name=models.CharField(verbose_name='name',max_length=64)
password=models.CharField(verbose_name='password',max_length=64)
token=models.CharField(verbose_name='token',max_length=64,null=True,blank=True)
4.5.2用户登入
class LoginView(APIView):
#不需要认证
authentication_classes = []
def post(self,request):
#获取用户通过POST方式传递过来的用户名和密码
name=request.data.get('name')
password=request.data.get('password')
print(name,password)
#尝试获取用户对象
user_obj=models.User.objects.filter(name=name,password=password).first()
if not user_obj:
#如果用户对象不存在,代表用户名密码错误
return Response({'status':False,'errMsg':'用户名或密码错误'})
#为用户生成一个token并保存到数据库
token=str(uuid.uuid4())
user_obj.token=token
user_obj.save()
return Response({'status':True,'token':token})
使用postman发送POST请求
4.5.2查看用户信息
# 视图类
class UserView(APIView):
# 需要认证
def get(self, request):
#返回用户名和token
return Response({'user':request.user.name,'token':request.auth})
#settings.py
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER": None,
#先认证URL参数中的token,如果认证失败则认证HTTP请求头部中的token,如果认证失败则进入未认证程序
"DEFAULT_AUTHENTICATION_CLASSES":["ext.auth.Query_Params_authentication",
"ext.auth.Header_authentication",
"ext.auth.Noauthentication",]
}
#ext.auth
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app_api import models
class Query_Params_authentication(BaseAuthentication):
"""
url参数认证:
1、读取请求url参数递过来的token
2、校验合法性
3、返回值
认证通过,则返回用户对象和token,不会进入下一个认证类
认证失败,返回None,进入下一个认证类
"""
def authenticate(self, request):
#从url参数中获取token
token=request.query_params.get('token')
if not token:
# 如果token不存在,返回None,进行下个认证类
return None
user_obj=models.User.objects.filter(token=token).first()
if user_obj:
#如果用户存在,不在进行下个认证类
return user_obj,token #request.user=user_obj,request.auth=token
#如果用户不存在,返回None,进行下个认证类
return None
def authenticate_header(self, request):
return "API"
class Header_authentication(BaseAuthentication):
"""
头部认证:
1、读取HTTP请求头部传递过来的token
2、校验合法性
3、返回值
认证通过,则返回用户对象和token,不会进入下一个认证类
认证失败,返回None,进入下一个认证类
"""
def authenticate(self, request):
#从HTTP请求问部获取token
token=request.META.get('HTTP_AUTHENTICATE')
if not token:
# 如果token不存在,返回None,进行下个认证类
return None
user_obj=models.User.objects.filter(token=token).first()
if user_obj:
#如果用户存在,不在进行下个认证类
return user_obj,token #request.user=user_obj,request.auth=token
#如果用户不存在,返回None,进行下个认证类
return None
def authenticate_header(self, request):
return "API"
class Noauthentication(BaseAuthentication):
"""
未通过上面两次认证的,直接抛出错误:
"""
def authenticate(self, request):
#如果以上的认证类认证全部失败,则抛出错误,认证失败。
raise AuthenticationFailed({'code':2000,'error':'认证失败'})
使用postman进行测试
1)url参数中传递token
2)HTTP头部传递token
3)token错误