认证组件

认证简介:

只有认证通过的用户才能访问指定的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中取 --->>> 默认配置

 

posted @ 2019-07-03 22:50  TianShu  Views(253)  Comments(0Edit  收藏  举报