rest_framework认证组件

问题:有些API,需要用户登录才能访问,有些无需登录就能访问。

解决:

  • a. 创建两个模型类:UserInfo---OneToOne---UsetToken

  • b. 登录成功后保存在数据库的UserToken表中

            # urls.py
    
            from django.urls import path
    from api import views urlpatterns = [
    path('api/v1/auth/',views.AuthView.as_view()),
    ] # views.py import hashlib, time
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from api import models def md5(username):
    """
    生成token
    :param username:
    :return:
    """
    m = hashlib.md5(username.encode('utf-8'))
    m.update(str(time.time()).encode('utf-8'))
    return m.hexdigest() class AuthView(APIView):
    """
    用户登录
    """ def post(self, request, *args, **kwargs):
    ret = {'code': 1000, 'msg': None}
    username = request._request.POST.get('username')
    password = request._request.POST.get('password') user = models.UserInfo.objects.filter(username=username, password=password).first()
    if not user:
    ret['msg'] = '用户名或密码错误'
    return Response(ret)
    token = md5(username)
    # 存在就更新,不存在就创建
    models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
    ret['code'] = 2000
    ret['msg'] = '登录成功'
    ret['token'] = token
    return Response(ret)
  • c. 创建自定义Auth认证类和订单,访问订单,判断是否携带token访问,不然不让访问


# urls.py urlpatterns = [
path('api/v1/auth/',views.AuthView.as_view()),
path('api/v1/order/',views.OrderView.as_view()),
] # views.py ORDERS = [
{
'id': '1',
'name': '华为MATE 20 Pro',
'price': 6999,
},
{
'id': '2',
'name': '一加6t',
'price': 3999,
},
{
'id': '3',
'name': '狗比亚',
'price': 2699,
},
] class Authentication(object):
"""
自定义认证类
""" def authenticate(self, request):
token = request._request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if not token_obj:
raise AuthenticationFailed('用户认证失败')
# 返回一个元祖 一个是用户对象。一个是token对象
return token_obj.user, token_obj def authenticate_header(self, request):
pass class OrderView(APIView):
"""
订单相关业务
"""
authentication_classes = [Authentication] def get(self, request, *args, **kwargs):
ret = {'code': 2000, 'msg': '获取成功', 'data': ORDERS}
return Response(ret)
  • d. 测试接口:只测试了正确的用户名和密码,错误的自己测

            import requests
    
            auth_url = 'http://127.0.0.1:8000/api/v1/auth/'
    res = requests.post(auth_url, data={'username': 'alex', 'password': 'root1234'}).json() print(res) # {'code': 2000, 'msg': '登录成功', 'token': '02fdedaa2c6c5773e00706b5890e289a'}
    token = res.get('token') order_url = 'http://127.0.0.1:8000/api/v1/order/'
    res = requests.get(order_url,params={'token':token}).json()
    print(res) # {'code': 2000, 'msg': '获取成功', 'data': [{'id': '1', 'name': '华为MATE 20 Pro', 'price': 6999}, {'id': '2', 'name': '一加6t', 'price': 3999}, {'id': '3', 'name': '狗比亚', 'price': 2699}]}
  • e. 再写一个API用户获取用户信息(通过认证通过后注册的request.user对象和request.token对象)


    urlpatterns = [
    path('api/v1/auth/',views.AuthView.as_view()),
    path('api/v1/order/',views.OrderView.as_view()),
    path('api/v1/user_info/',views.UserInfoView.as_view()),
    ] class UserInfoView(APIView):
    """
    获取用户信息相关
    """
    authentication_classes = [Authentication] def get(self, request, *args, **kwargs):
    data = {
    'username': request.user.username,
    'token': request.auth.token
    }
    ret = {'code': 2000, 'msg': '获取成功', 'data': data}
    return Response(ret)
  • f. 测试认证成功之后返回元祖的两个对象


    import requests auth_url = 'http://127.0.0.1:8000/api/v1/auth/'
    res = requests.post(auth_url, data={'username': 'alex', 'password': 'root1234'}).json() print(res) # {'code': 2000, 'msg': '登录成功', 'token': '05810e2756bc6cc27c1ce3af827aa45f'}
    token = res.get('token') order_url = 'http://127.0.0.1:8000/api/v1/user_info/'
    res = requests.get(order_url,params={'token':token}).json()
    print(res) # {'code': 2000, 'msg': '获取成功', 'data': {'username': 'alex', 'token': '05810e2756bc6cc27c1ce3af827aa45f'}}

全局使用(再次看源码)

      def get_authenticators(self):
return [auth() for auth in self.authentication_classes] authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES def reload_api_settings(*args, **kwargs):
setting = kwargs['setting']
if setting == 'REST_FRAMEWORK':
api_settings.reload()
# 所以通过配置api.settings可达到全局使用的效果
  • 全局使用
   # 在api应用下面创建utils\auth.py 把之前写的自定义类剪切过来
# utils\auth.py
from api import models
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication class Authentication(BaseAuthentication):
"""
自定义认证类
""" def authenticate(self, request):
token = request._request.GET.get('token')
token_obj = models.UserToken.objects.filter(token=token).first()
if not token_obj:
raise AuthenticationFailed('用户认证失败')
# 返回一个元祖 一个是用户对象。一个是token对象
return token_obj.user, token_obj def authenticate_header(self, request):
pass
# settings.py
##############rest_framework配置################
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.Authentication']
}
# views.py
import hashlib, time
from rest_framework.views import APIView
from rest_framework.response import Response
from api import models ORDERS = [
{
'id': '1',
'name': '华为MATE 20 Pro',
'price': 6999,
},
{
'id': '2',
'name': '一加6t',
'price': 3999,
},
{
'id': '3',
'name': '狗比亚',
'price': 2699,
},
] def md5(username):
"""
生成token
:param username:
:return:
"""
m = hashlib.md5(username.encode('utf-8'))
m.update(str(time.time()).encode('utf-8'))
return m.hexdigest() class AuthView(APIView):
"""
用户登录
"""
# 不需要认证为空列表即可
authentication_classes = [] def post(self, request, *args, **kwargs):
ret = {'code': 1000, 'msg': None}
username = request._request.POST.get('username')
password = request._request.POST.get('password') user = models.UserInfo.objects.filter(username=username, password=password).first()
if not user:
ret['msg'] = '用户名或密码错误'
return Response(ret)
token = md5(username)
# 存在就更新,不存在就创建
models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
ret['code'] = 2000
ret['msg'] = '登录成功'
ret['token'] = token
return Response(ret) class OrderView(APIView):
"""
订单相关业务
""" def get(self, request, *args, **kwargs):
ret = {'code': 2000, 'msg': '获取成功', 'data': ORDERS}
return Response(ret) class UserInfoView(APIView):
"""
获取用户信息相关
""" def get(self, request, *args, **kwargs):
data = {
'username': request.user.username,
'token': request.auth.token
}
ret = {'code': 2000, 'msg': '获取成功', 'data': data}
return Response(ret)

梳理:

  • 全局使用:创建自定义认证类,继承BaseAuthentication,实现:authenticate()

  • 局部使用(使用自带的认证类):authentication_classes = [BasicAuthentication,]

  • 该方法有三种返回值

    1. None 当前认证类不做认证,交给下一个认证来来执行
    2. 抛出异常 raise AuthenticationFailed('用户认证失败')
    3. 元祖(元素1,元素2):元素1赋值给request.user;元素2赋值给request.token
  • 注意:当所有认证类都返回None时,此时是匿名用户,默认是AnonymousUser,可以通过配置文件来更改显示

    REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.FirstAuthtication','api.utils.auth.Authtication', ],
#"UNAUTHENTICATED_USER":lambda :"匿名用户",
"UNAUTHENTICATED_USER":None, # 匿名,request.user = None
"UNAUTHENTICATED_TOKEN":None,# 匿名,request.auth = None
}

源码流程

  1. dispath()-->initialize_request()

    - 封装request对象,获取认证类(全局&局部),通过列表生成式创建认证类对象

  2. initial-->perform_authentication()-->request.user

    - for循环每个认证类 return

  3. 认证成功基于反射根据method不同做不同处理

002---rest_framework认证组件的更多相关文章

  1. Django的rest_framework认证组件之全局设置源码解析

    前言: 在我的上一篇博客我介绍了一下单独为某条url设置认证,但是如果我们想对所有的url设置认证,该怎么做呢?我们这篇博客就是给大家介绍一下在Rest_framework中如何实现全局的设置认证组件 ...

  2. Django的rest_framework认证组件之局部设置源码解析

    前言: Django的rest_framework组件的功能很强大,今天来我来给大家剖析一下认证组件 下面进入正文分析,我们从视图开始,一步一步来剖析认证组件 1.进入urls文件 url(r'^lo ...

  3. rest_framework -- 认证组件

    #####认证组件##### 一.认证是什么就不说了,某些网页必须是用户登陆之后,才能访问的,所以这时候就需要用上认证组件. 你不用rest_framework的认证组件也行,这种认证的话,完全可以自 ...

  4. Django之REST_FRAMEWORK 认证组件

    Django之DRF之认证组件 # from rest_framework.views import APIView # APIView 中的 dispatch 中 执行的 self.initial( ...

  5. rest_framework 认证组件 权限组件

    认证组件 权限组件 一.准备内容 # models class User(models.Model): name = models.CharField(max_length=32) pwd = mod ...

  6. DRF认证组件

    1.DRF认证组件之视图注册用法(自定义简单使用) settings.py配置 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.a ...

  7. Django-restframework 源码之认证组件源码分析

    Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...

  8. drf视图组件、认证组件

    视图组件 1.基本视图 url(r'^publish/$', views.PublishView.as_view()), url(r'^publish/(?P<pk>\d+)/$', vi ...

  9. DjangoRestFramework学习三之认证组件、权限组件、频率组件、url注册器、响应器、分页组件

    DjangoRestFramework学习三之认证组件.权限组件.频率组件.url注册器.响应器.分页组件   本节目录 一 认证组件 二 权限组件 三 频率组件 四 URL注册器 五 响应器 六 分 ...

随机推荐

  1. MYSQL数据库、用户、表等基础构建

    MYSQL数据库.用户.表等基础构建: 1.->:创建数据库: 1.1. create schema [数据库名称] default character set utf8 collate utf ...

  2. windows完全卸载office

    运行文件O15CTRRemove.diagcab执行完全卸载. 文件下载地址:https://pan.baidu.com/s/1eSilUJS

  3. SQL简单基础(2)

    查询功能是SQL语句最重要的功能,查询操作也是数据库系统最常用的操作.学习SQL查询语句,首先要弄清楚的是查询语句用到的关键字以及查询语句的执行顺序.SQL语言的一个特点在于,它是一种声明式语句,执行 ...

  4. python内置模块(三)

    hashlib模块 通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示). Python2中使用hashlib: import hashlib m = hashlib ...

  5. video文件格式说明(笔记)

    video标签兼容IE8可使用html5media.js,具体demo可以下载文件中的压缩包 移动端兼容参考: http://www.xyhtml5.com/3252.html

  6. SpringBoot实战(七)之与Redis进行消息传递

    此次教程演示安装的是Window版的Redis, Linux安装Redis可以参考我的这篇博文:Redis的安装和客户端使用注意事项 关于Java连接Redis操作方面可以参考我的这篇博文:Java连 ...

  7. 链表推导式 【list comprehension】

    x for x in x 链表推导式 [list comprehension]链表推导式提供了一个创建链表的简单途径,无需使用 map(), filter() 以及 lambda.返回链表的定义通常要 ...

  8. PAT——1033. 旧键盘打字

    旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在2行中分别给出坏掉的那些键.以及应该输入的文 ...

  9. [LuoguP1053][Noip2005]篝火晚会

    [LuoguP1053][Noip2005]篝火晚会(Link) 现在你有一个排成一个圈的\(N\)大小的队列,一开始的顺序是\(\{1,2,3,4...N\}\),一共有\(N\)个要求,第\(i\ ...

  10. SDOI2018 一轮培训划水祭

    \(\mathcal{Day \ \ -3}\) 作为前言来讲,我对于过几天的省选培训还是很期待的--就算我的实力根本不够,名额是学校推荐的,但是能见到\(\mathcal{cwbc}\)以及一众大佬 ...