笔记: Django Rest Framework APIView 认证类自定义 使用流程概述

验证类可以局部使用(在单独的views中引入), 也可以全局使用(在settings中配置)

使用流程1: 就是先定义一个自定义的认证类(比如MyAuth),然后重写authenticate()方法,把需要认证的逻辑放到这个函数里面写,然后注意返回值是一个元组. 然后在需要使用这个验证类的view视图里面 用authentication_classes = [MyAuth,]列表包裹起来,就可以了.

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用流程2: 上述使用在需要的视图里面写上认证类的列表. 如果视图过多,则写的也多…所以还可以放到settings.py 文件中, 如下格式:

TIPS: 如果在全局中设置了认证类,表示所有的视图都会经过这个认证类,那么如果一些视图需要这个认证类,就只能在这个视图中单独设置authentication_classes = [] 就是这个列表为空,表示不处理.

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES	
REST_FRAMEWORK = {
	#全局使用的认证类
    'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.FirstAuthenticate']  #注意这个格式, 这里的DEFAULT_AUTHENTICATION_CLASSES是restframework 配置规定的, 后面的列表就是认证的类. 里面写的是认证类的路径
    #下面两句是匿名用户的设置:
    'UNAUTHENTICATED_USER':None, #匿名, 则request.user = None
    'UNAUTHENTICATED_TOKEN':None #匿名, 则request.token = None
}

验证登陆是不是成功
在这里插入图片描述

自定义验证类, 继承BaseAuthentication, 这里继承这个类的好处就是我们只需要写一个authenticate()就可以了,另外一个因为是继承的关系,父类已经有了,就不用重写了,如下:
class MyAuthenticate1(BaseAuthentication):
    def authenticate(self, request):
        #验证用户带过来的token
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        print(token)
        print(token_obj)
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')

        return (token_obj.user, token_obj) #必须返回一个元组, restframeworkd会见两个字段赋值给request,一共后续使用.

    def authenticate_header(self, request):
        pass

总结流程

第一步: 创建一个认证类: 继承自 BaseAuthentication 实现authenticate方法

  • 返回值 有三种:
    • None, 表示我不处理,留给下一个认证类处理.
    • 失败, raise exceptions.AuthenticationFailed(‘用户认证失败’)
    • 成功 会返回一个二元组, (元素1, 元素2) 他们将会赋值给request.user, request.auth

认证类的两种适用范围:

  • 一种 局部使用, 只在特定试图中引用使用
  • 全局使用, 在settings中写定

源代码如下:

项目的目录结构如下图:
在这里插入图片描述
1, models.py 如下:

from django.db import models

class UserInfo(models.Model):
    user_type_choices = (
        (1, '普通用户'),
        (2, 'VIP'),
        (3, 'SVIP')
    )
    user_type = models.IntegerField(choices=user_type_choices)
    username = models.CharField(max_length=32, unique=True)
    password = models.CharField(max_length=64)

class UserToken(models.Model):
    user = models.OneToOneField(to=UserInfo, on_delete=models.CASCADE)
    token = models.CharField(max_length=64)

2, urls.py 如下:

from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from api import views

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^api/v1/auth/$', views.AuthView.as_view()),
    url(r'^api/v1/order/$', views.OrderView.as_view())
]

3, views.py

from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BasicAuthentication, BaseAuthentication
from rest_framework import exceptions
from api import models
from api.utils.auth import FirstAuthenticate

#这个md5函数采用用户和时间来生成md5的随机值,用来生成token
def md5(user):
    import hashlib
    import time
    ctime = str(time.time())
    m = hashlib.md5(bytes(user, encoding='utf-8'))
    m.update(bytes(ctime, encoding='utf-8'))
    return m.hexdigest()

class AuthView(APIView):
    '''
    用于用户登陆
    这里拿到前台发过来的用户名和密码,然后去数据库校验,同时我们还生成了token,然后还给用户返回了token,用于用户后面发送请求,必须要
    带上这个token的请求.
    '''
    authentication_classes = [] #这里因为在全局中设置了验证类,所以在这里要把这个列表为空,好让这个视图可以不经过全局的验证,直接执行.
    def get(self, request, *args, **kwargs):
        return HttpResponse('hello workd')

    def post(self, request, *args, **kwargs):
        ret = {'code':1000, 'msg':None}
        try:
            user = request._request.POST.get('username')
            password = request._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=user, password=password).first()
            if not obj:
                ret['code'] = 1001
                ret['msg'] = '用户名或者密码错误'
            #未登陆用户创建token,采用上面定义的md5()函数来生成token
            token = md5(user)
            #保存金数据库,有就更新,没有就创建,因为是只能用最新的token,所以需要更新操作.
            models.UserToken.objects.update_or_create(user=obj, defaults={'token':token})
            #需要给用户返回token
            ret['token'] = token
        except Exception as e:
            ret['code']=1002
            ret['msg']='请求异常'


        return JsonResponse(ret)


#定义一个订单的字典, 用字典模拟订单
ORDER_DICT= {
    1: {
        'name': '购买力平价',
        'age': 12,
        'gender': '男',
        'content': '...'
    },
    2: {
        'name': '假数据',
        'age': 12,
        'gender': '男',
        'content': '...'
    },
}

#自定义验证类, 没有继承
class MyAuthenticate(object):
    def authenticate(self, request):
        #验证用户带过来的token
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        print(token)
        print(token_obj)
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')

        return (token_obj.user, token_obj) #必须返回一个元组, restframeworkd会见两个字段赋值给request,一共后续使用.

    def authenticate_header(self, request):
        pass


#自定义验证类, 继承BaseAuthentication, 这里继承这个类的好处就是我们只需要写一个authenticate()就可以了,另外一个因为是继承的关系,父类已经有了,
#就不用重写了.
class MyAuthenticate1(BaseAuthentication):
    def authenticate(self, request):
        #验证用户带过来的token
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        print(token)
        print(token_obj)
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')

        return (token_obj.user, token_obj) #必须返回一个元组, restframeworkd会见两个字段赋值给request,一共后续使用.

    def authenticate_header(self, request):
        pass



class OrderView(APIView):

    authentication_classes = [FirstAuthenticate, MyAuthenticate,] #用restframework的认证类做的, 格式: 首先写一个认证类,然后在这里这样用就可以了,逻辑代码在上面的自定义认证类中实现.

    def get(self, request, *args, **kwargs):
        print(request.user)
        print(request.auth)
        ret = {'code':1000, 'msg':None, 'data':None} #用于标实是不是请求成功 和数据
        #标记用户登陆了才可以看到这里的数据,否则看不到数据
        #这里就用上面说的token,,因为只有登陆了,才会生成token,才标实用户已经登陆了,否则没有token,就表示用户没有登陆
        #这里的认证方法比较传统,没有用到restframework的认证类,如果有很多视图,则需要在每个视图中间都要写这个认证函数,
        #我们可以自定义一个验证类,然后重写authenticate()方法,把验证登陆的语句写在里面,然后在这里是需要调用就可以了.一劳永逸
        # token = request._request.GET.get('token')
        # if not token:
        #     return HttpResponse('用户未登录,无法查看')

        try:
            ret['data'] = ORDER_DICT

        except Exception as e:
            pass

        return JsonResponse(ret)

4, 自定义验证类 路径: api/utils/auth.py

from rest_framework import exceptions
from api import models



#自定义验证类
class FirstAuthenticate(object):
    def authenticate(self, request):
        #验证用户带过来的token
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        print(token)
        print(token_obj)
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')

        return (token_obj.user, token_obj) #必须返回一个元组, restframeworkd会见两个字段赋值给request,一共后续使用.

    def authenticate_header(self, request):
        pass

5, settings.py 文件如下:

"""
Django settings for auth2 project.

Generated by 'django-admin startproject' using Django 3.0.5.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'p)rim!kr+qd(&x$b&p9!%6nwelaw%x)^y6optft1($79h@idro'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'auth2.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join (BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'auth2.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.FirstAuthenticate',],  #注意这个格式, 这里的DEFAULT_AUTHENTICATION_CLASSES是restframework 配置规定的, 后面的列表就是认证的类. 里面写的是认证类的路径
    #下面两句是匿名用户的设置:
    'UNAUTHENTICATED_USER':None, #匿名, 则request.user = None
    'UNAUTHENTICATED_TOKEN':None #匿名, 则request.token = None
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值