认证组件
认证简介:
只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录,就不能查看,这时候需要用到认证组件
需求:写一个简单的登录认证接口:
先创建好表格:
class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=64) user_type = models.IntegerField(choices=((1, "超级管理员"), (2, "普通管理员"), (3, "2b用户")), default=3) # 跟User表做一对一关联 class Token(models.Model): user = models.OneToOneField(to='User') token = models.CharField(max_length=64)
在视图函数中:
from app01 import models from django.core.exceptions import ObjectDoesNotExist # 异常捕获:对象不存在 import uuid # 生成唯一的id class Login(APIView): def post(self, request): response = {'code': 100, 'msg': '登录成功'} name = request.data.get('name') pwd = request.data.get('pwd') try: # get 有且只有一条才不报错,其他都抛异常 user = models.User.objects.filter(name=name, pwd=pwd).get() # 登录成功,需要去token表中存数据 # 生成一个唯一的随机字符串: 这用uuid token = uuid.uuid4() # update_or_create查出来的token,存在就更新,不存在就创建 models.Token.objects.update_or_create(user=user, defaults={'token': token}) response['token'] = token except ObjectDoesNotExist as e: response['code'] = 101 response['msg'] = '用户名或密码错误' except Exception as e: # 捕获所有的异常 response['code'] = 102 response['msg'] = str(e) # 把异常信息返回到前端 return Response(response)
配置路由:
url(r'^login/', views.Login.as_view())
效果演示:
登录失败展示,用户名错误,然后需要注意的是在访问路由的时候,/login后面一定要加上斜杠,不加会报错
登录成功(用户名与密码都正确),然后返回了唯一的id:token,在访问获取图书接口的时候需要用它来认证是否登录,登录了才可以访问
认证组件的使用
1、在应用名下新建一个py文件写一个认证类,继承BaseAuthentication
重写authenticate方法,把request对象传入。能从request对象中取出用户携带的token,根据token判断是否登录过,如果登陆过,返回两个值user对象,token对象,如果没有登录就抛异常
myauth.py中:
用户登录成功才能够访问所有图书接口,所有首先要获取用户登录的token,然后做校验,如果相同就表示已经登录,就能获取到图书接口
from app01 import models from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed # 异常捕获 class MyAuth(BaseAuthentication): # 继承基类BaseAuthentication,重写了authenticate方法,把request对象传入,能从request对象中取出用户携带的token def authenticate(self, request): # 写认证逻辑 token = request.GET.get('token') token_obj = models.Token.objects.filter(token=token).first() if token_obj: # 有值表示已经登录 # token_obj.user 当前登录的user对象,如果这里不返回,视图类里就拿不到request.user.name,就是当前用户对象,所以要返回 return token_obj.user, token_obj else: # 没有表示没有登录 raise AuthenticationFailed('没有登录')
视图函数中:调用了MyAuth类
from rest_framework.views import APIView from rest_framework.response import Response from app01.myauth import MyAuth # 用户必须登录之后才能访问获取所有图书接口 class Books(APIView): authentication_classes = [MyAuth, ] # []里可以写多个认证类 def get(self, request): # request.user就是当前登录用户,前面必须返回才能获取到 print(request.user.name) return Response('返回了所有的图书')
路由配置:
url(r'^books/', views.Books.as_view())
效果演示:
如果token校验成功,就登录认证成功,返回了所有图书,如果校验失败,就抛异常:没有登录
2、局部使用
在每个类视图类里面写:authentication_classes = [MyAuth,]
3、全局使用
在settings里配置,所有的视图类都需要认证,就不需要在视图类写了
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.myauth.MyAuth', ] }
4、局部禁用
但是登录视图类不需要认证,这时候就要用到局部禁用,在视图类里面写上:authentication_classes = []
源码分析:
APIView里面的dispatch里面的initial里面的perform_authentication
点开perform_authentication去里面看一下
request是新的request,user是一个方法,被封装成一个数据属性,那这个类我们怎么去找呢?我们需要去Request里面找这个user
点进去看一下authenticators是什么
authenticators是Request类实例化的回收传过来的
然后再找Request是在哪里实例化的 是在封装的时候实例化的,去看一下
然后点进去看看get_authenticators执行了什么
那么这个返回装有一个个对象的列表被谁接收了?
然后这个selr.authenticators又把值返回给了
通过for循环取出一个个对象,然后对象又调用authenticate方法
调用的是认证类里面写的autnenticate方法,开始写认证逻辑
总结
读源码看到的东西:
如果在项目的setting.py中配置了REST_FRAMEWORK,默认先从项目的setting中取
如果取不到,才去默认的drf配置文件中取
如果用户在视图类中配置了某个,先去用户配置的取
总结:
先取视图类中配置的 --->>> 项目setting中取 --->>> 默认配置