登录的token操作
#app.models.py :表结构
from django.db import models
class User(models.Model):
user = models.CharField(max_length=32)
password = models.CharField(max_length=32)
def __str__(self):
return self.user
class UserToken(models.Model):
token = models.CharField(max_length=64)
user = models.OneToOneField(to='User')
#app.objectjson.py :序列化模块
from rest_framework import serializers
from app import models
class UserJson(serializers.ModelSerializer):
class Meta:
model = models.User
fields = '__all__'
#app.views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app import models, common, objectjson
class Login(APIView):
def post(self, request):
data_dic = request.data
user = models.User.objects.filter(**data_dic).first()
if user:
# 登录成功操作token
token = common.get_token()
# token的数据库操作,第一次产生token是新建,再次就是更新
models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
user_data = objectjson.UserJson(user).data
return Response({
'status': 0,
'message': 'login success',
'token': token, # 将token返回给前台
'results': user_data
})
return Response({
'status': 1,
'message': 'login failedr'
})
认证方法的实现
#源码分析
# as_view()=> APIView.dispatch => self.initial(request,*args,**kwargs) => 封装后的drf的request => request.user => self._authenticate() => authenticate(self,reuquest)的源码根据地
#app.views.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class LoginAuthenticate(BaseAuthentication):
def authenticate(self, request):
# 登录逻辑:如果用户登录了,登录操作产生了token,且前后台同步了
# 登录判断:再次发生请求,没有token代表没登录,错误token,代表无效的登录,token正确才是正常的登录用户
# 如何将token取出,规定token用请求头传递
token = request.META.get('HTTP_TOKEN')
result = models.UserToken.objects.filter(token=token).first()
print(result)
if result:
# 认证通过,可以返回None(有多个认证时),可以返回两个值:user,auth
return result.user, token
else:
# 认证失败,抛出APIException或其子类对象
raise AuthenticationFailed('认证失败')
class Books(APIView):
authentication_classes = [LoginAuthenticate]
# 视图函数处理的逻辑
def get(self, request):
# 通过认证后,用request.user拿到当前登录的用户,用request.auth拿到认证值(该值通常自定义)
print(request.user)
return Response({
'status': 0,
'message': 'ok',
'results': []
})
局部认证
#app.auth.py 完成校验的所有逻辑
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app import models
class LoginAuthenticate(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
result = models.UserToken.objects.filter(token=token).first()
print(result)
if result:
return result.user, token
else:
raise AuthenticationFailed('认证失败')
class Books(APIView):
#添加登录认证即可
authentication_classes = [auth.LoginAuthenticate]
def get(self, request):
print(request.user)
return Response({
'status': 0,
'message': 'ok',
'results': []
})
全局认证
# 1.在settings.py中配置
# 全局认证
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
'app.auth.LoginAuthenticate'
),
}
#2.所有的CBV类都不需要添加类属性:authentication_classes
# 局部禁用
# 3.在不需要认证的CBV类中添加类属性:authentication_classes =[]
注销:在全局认证情况下
class Logout(APIView):
# 在全局认证情况下,如果能走get方法,代表已经通过登录认证(登录状态),就可以注销
def get(self, request):
models.UserToken.objects.update_or_create(user=request.user, defaults={'token': common.get_token()})
return Response({
"status": 0,
"msg": 'logout success',
})