DRF之认证
一. DRF认证
局部认证组件
我们知道,我们不管路由怎么写的,对应的视图类怎么写的,都会走到dispatch方法,进行分发,
在咱们看的APIView类中的dispatch方法的源码中,有个self.initial(request, *args, **kwargs),那么认证、权限、频率这三个默认组件都在这个方法里面了,如果我们自己没有做这三个组件的配置,那么会使用源码中默认的一些配置。进源码去看看你就会看到下面三个东西:
# Ensure that the incoming request is permitted #实现认证 self.perform_authentication(request) #权限判断 self.check_permissions(request) #控制访问频率 elf.check_throttles(request)
models:
首先我们需要创建一个表,用户表,里面放一个token字段,其实一般我都是放到两个表里面,和用户表是一个一对一关系的表,看代码:
from django.db import models # Create your models here. class UserInfo(models.Model): username = models.CharField(verbose_name='用户名', max_length=32) password = models.CharField(verbose_name='密码', max_length=32) class UserToken(models.Model): user = models.OneToOneField('UserInfo', on_delete=models.CASCADE) token = models.CharField(verbose_name='token值', max_length=64)
做了一层路由分发:
path('auth/', include('authDemo.urls'))
urls:
from django.urls import path from authDemo.views import DemoView,AuthDemo,TestView urlpatterns = [ path('', DemoView.as_view()), path('login', AuthDemo.as_view()), path('test', TestView.as_view()) ]
自定义认证类:
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from authDemo import models class MyAuth(BaseAuthentication): def authenticate(self, request): request_token = request.query_params.get("token", None) if not request_token: raise AuthenticationFailed({"code": 1001, "error": "缺少token"}) token_obj = models.UserToken.objects.filter(token=request_token).first() if not token_obj: raise AuthenticationFailed({"code": 1001, "error": "无效的token"}) return token_obj.user, token_obj.token
views:
from uuid import uuid4 from django.shortcuts import render from django.http import JsonResponse from rest_framework.views import APIView from rest_framework.response import Response from authDemo import models from utiles.auth import MyAuth # Create your views here. class DemoView(APIView): def get(self, request): return Response('认证DEMO') class AuthDemo(APIView): def post(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': None} try: username = request.data.get('user') password = request.data.get('pwd') user_obj = models.UserInfo.objects.filter(username=username, password=password).first() if not user_obj: ret['code'] = 2001 ret['msg'] = '用户名或密码错误!' return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) uuid = str(uuid4()) models.UserToken.objects.update_or_create(user=user_obj, defaults={'token': uuid}) ret['token'] = uuid except Exception as e: ret['code'] = 2000 ret['msg'] = '请求异常' return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii': False}) class TestView(APIView): authentication_classes = [MyAuth,] def get(self, request): print(request.user) print(request.auth) # user_id = request.user.id return Response("认证测试")
其实最最要的步骤就是:
1.自定义认证类,继承了 BaseAuthentication 之后,还需要实现 authenticate(self, request): 这个方法,并且返回值一定的是一个元组。
#源码中会发现,这个方法会有两个返回值,并且这两个返回值封装到了新的request对象中了,request.user-->用户名 和 request.auth-->token值,这两个值作为认证结束后的返回结果
2.视图中应用 authentication_classes = [MyAuth,] 这就是局部应用上了我们自己写的认证类。
全局视图认证组件
配置settings文件:
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth"] #里面是路径字符串
}
如果配置了全局认证类后,想在某个试图中不进行认证的话,可以 authentication_classes = [ ]传一个空列表