如果需要全局使用
-在setting中配置: REST_FRAMEWORK={ 'DEFAULT_AUTHENTICATION_CLASSES':['app01.MyAuth.LoginAuth',] } -局部禁用: -在视图类中加一行: -authentication_classes = []
1,配置登录路由
url(r'^login/', views.Login.as_view()),
2,视图层
from django.shortcuts import render from rest_framework.views import APIView from app01 import models # 认证的时候,用户名或者密码错误时的报错信息,需要来接收 from django.core.exceptions import ObjectDoesNotExist # 产生随机字符串(为了产生唯一的一个,就在它的后面添加时间的代码) import hashlib import time from django.http import JsonResponse from app01.MyAuth import LoginAuth # Create your views here. def get_token(name): # 生成一个md5对象(里面添加的值必须是bytes类型) md5 = hashlib.md5() # time.time()生成时间戳类型,必须装成字符串,再编码成bytes格式 # encoding='utf8'和encode('utf8')是一样的结果 md5.update(str(time.time()).encode('utf-8')) md5.update(name.encode('utf-8')) return md5.hexdigest() class Login(APIView): # 局部使用 authentication_classes = [LoginAuth, ] def post(self, request, *args, **kwargs): response = {'status': 100, 'msg': '登录成功'} name = request.data.get('name') pwd = request.data.get('pwd') try: # 验证用户是否登录成功 user = models.UserInfo.objects.get(name=name, pwd=pwd) # 如果检验通过,则生成一个随机字符串(身份标识)token token = get_token(name) # 需要保存到数据库(update_or_create更新或者是创建) models.UserToken.objects.update_or_create(user=user, defaults={'token': token}) response['token'] = token except ObjectDoesNotExist as e: response['status'] = 101 response['msg'] = '用户名或者密码错误' except Exception as e: response['status'] = 102 # response['msg'] = '未知错误' response['msg'] = str(e) return JsonResponse(response, safe=False)
3,在自定义的认证功能层
from app01 import models #如果认证不通过则需要抛异常的模块 from rest_framework import exceptions # 需要继承的父类 from rest_framework.authentication import BaseAuthentication # 用drf认证写一个类 class LoginAuth(BaseAuthentication): # 函数名一定不能改变,必须接受两个参数,第二个是reqeust对象 def authenticate(self, request): # 从request对象中取出token(也可以从其他地方取) # 要把数据放在请求头里面127.0.0.1:8000/login/?token=ac350193de561228156e041728ad9937 token = request.query_params.get('token') # 取数据库中过滤查询 ret = models.UserToken.objects.filter(token=token).first() if ret: # 如果ret 存在则说明认证通过(如果不存在返回值,可以进行下一个认证,) # ret.user就是当前登录用户对象(返回值是当前登录用户对象和token的query_set对象) return ret.user, ret raise exceptions.APIException('认证不通过')
二,源码分析
原文:https://blog.csdn.net/qq_42721964/article/details/84929033
APIView—>APIView的dispatch方法—>到dispatch方法下的self.initial(request, *args, **kwargs)---->APIView的initial方法下的self.perform_authentication(request),可以看到这个方法执行了request.user,这是Request类下的一个方法通过@property伪装成了属性,进入这个方法----->执行self._authenticate()---->for authenticator in self.authenticators这里的authenticators是不是很熟悉,就是initialize_request这个方法下Request实例化时authenticators=self.get_authenticators(),---->执行了get_authenticators(),最后执行了authenticate方法。