引言

很久很久以前,Web站点只是作为浏览服务器资源(数据)和其他资源的工具,甚少有什么用户交互之类的烦人的事情需要处理,所以,Web站点的开发这根本不关心什么人在什么时候访问了什么资源,不需要记录任何数据,有客户端请求,我即返回数据,简单方便,每一个http请求都是新的,响应之后立即断开连接。

而如今,互联网的世界发生了翻天覆地的变化,用户不仅仅需要跟其他用户沟通交流,还需要跟服务器交互,不管是论坛类、商城类、社交类、门户类还是其他各类Web站点,大家都非常重视用户交互,只有跟用户交互了,才能进一步留住用户,只有留住了用户,才能知道用户需求,知道了用户需求,才会产生商机,有了用户,就等于有了流量,才能够骗到…额…是融到钱,有了资金企业才能继续发展,可见,用户交互是非常重要的,甚至可以说是至关重要的一个基础功能。

而谈到用户交互,则必须要谈到我们今天所要学习的知识点,认证、权限和频率。首先我们来看看认证。

认证组件

使用token

大部分人都知道cookie和session这两种方式可以保存用户信息,这两种方式不同的是cookie保存在客户端浏览器中,而session保存在服务器中,他们各有优缺点,配合起来使用,可将重要的敏感的信息存储在session中,而在cookie中可以存储不太敏感的数据。

而token称之为令牌。cookie、session和token都有其应用场景,没有谁好谁坏,不过开发数据接口类的Web应用,目前用token还是比较多的。

token认证的大致步骤是这样的:

  • 用户登录,服务器端获取用户名密码,查询用户表,如果存在该用户且第一次登录(或者token过期),生成token,否则返回错误信息
  • 如果不是第一次登录,且token未过期,更新token值

定义 url

from django.urls import path, re_path

from DrfOne import views

urlpatterns = [

    path("books/", views.BookView.as_view({
"get": "list",
"post": "create",
})),
re_path('books/(?P<pk>\d+)/', views.BookView.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
})), # 登陆
path('login/', views.LoginView.as_view()),
]

创建两个 model ,如下所示:

from django.db import models

class UserInfo(models.Model):
username = models.CharField("姓名", max_length=32)
password = models.CharField("密码", max_length=32)
age = models.IntegerField("年龄")
gender = models.SmallIntegerField("性别", choices=((1, "男"), (2, "女")), default=1)
user_type_entry = ((1, "普通用户"), (2, "VIP"), (3, "SVIP"))
user_type = models.SmallIntegerField("用户级别", choices=user_type_entry) def __str__(self):
return self.username class UserToken(models.Model):
user = models.ForeignKey(to="UserInfo", on_delete=models.CASCADE)
token = models.CharField(max_length=128)

post 方法接口,视图类如下所示:

from django.http import JsonResponse

from rest_framework.views import APIView

from DrfTwo.models import UserInfo, UserToken

class LoginView(APIView):
def post(self, request):
# 定义返回信息
ret = dict()
try:
# 定义需要的信息
fields = {"username", "password"}
# 定义一个用户信息字典
user_info = dict()
# 判断fields是否是request.data的子集
if fields.issubset(set(request.data.keys())):
for key in fields:
user_info[key] = request.data.get(key) user_instance = UserInfo.objects.filter(**user_info).first()
# 用户验证
if user_instance:
# 自定义generate_token()方法,获取token值,在后面
access_token = generate_token()
# 用户登陆成功,创建token,token存在更新token, defaults为更新内容
UserToken.objects.update_or_create(user=user_instance, defaults={
"token": access_token
})
ret["status_code"] = 200
ret["status_message"] = "登录成功"
ret["access_token"] = access_token
ret["user_role"] = user_instance.get_user_type_display() else:
ret["status_code"] = 201
ret["status_message"] = "登录失败,用户名或密码错误"
except Exception as e:
ret["status_code"] = 202
ret["status_message"] = str(e) return JsonResponse(ret)

简单写了个获取随机字符串的方法用来生成token值:

import uuid

def generate_token():
random_str = str(uuid.uuid4()).replace("-", "")
return random_str

以上就是token的简单生成方式,当然,在生产环境中不会如此简单,关于token也有相关的库,然后在构造几条数据之后,可以通过POSTMAN工具来创建几个用户的token信息。

接下来,如何对已经登录成功的用户实现访问授权呢?也就是说,只有登录过的用户(有token值)才能访问特定的数据,该DRF的认证组件出场了

认证组件的使用

首先,新建一个认证类,之后的认证逻辑就包含在这个类里面:

# 1.定义认证类
class UserAuth(object):
# 认证逻辑
def authenticate(self, request):
user_token = request.GET.get('token') token_object = UserToken.objects.filter(token=user_token).first()
if token_object:
return token_object.user, token_object.token
else:
raise APIException("认证失败")

实现方式看上去非常简单,到 token 表里面查看 token 是否存在,然后根据这个信息,返回对应信息即可,然后,在需要认证通过才能访问的数据接口里面注册认证类即可:

from rest_framework.viewsets import ModelViewSet
from rest_framework.exceptions import APIException from DrfOne.models import Book, UserToken
from DrfOne.drf_serializers import BookSerializer # 1.定义认证类
class UserAuth(object):
# 认证逻辑
def authenticate(self, request):
user_token = request.GET.get('token') token_object = UserToken.objects.filter(token=user_token).first()
if token_object:
return token_object.user.username, token_object.token
else:
raise APIException("认证失败") class BookView(ModelViewSet):
# 2.指定认证类,固定写法
authentication_classes = [UserAuth]
# 获取数据源, 固定写法
queryset = Book.objects.all()
# 序列化类, 固定写法
serializer_class = BookSerializer

序列类 BookSerializer

from rest_framework import serializers

from DrfOne import models

class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__" extra_kwargs = {
# 仅写
"publish": {'write_only': True},
"authors": {'write_only': True},
} publish_name = serializers.CharField(max_length=32, read_only=True, source="publish.name")
publish_address = serializers.CharField(max_length=32, read_only=True, source="publish.address")
author_name = serializers.SerializerMethodField() def get_author_name(self, book_obj):
author_list = list()
for author in book_obj.authors.all():
# 注意列表添加字段,author.name而不是author
author_list.append(author.name)
return author_list

类BookSerializer

多个认证类

需要注意的是,如果需要返回什么数据,请在最后一个认证类中返回,因为如果在前面返回,在源码的 self._authentication() 方法中会对返回值进行判断,如果不为空,认证的过程就会中止,多个认证类的实现方式如下:

# 1.定义认证类
class UserAuth(object):
# 认证逻辑
def authenticate(self, request):
user_token = request.GET.get('token') token_object = UserToken.objects.filter(token=user_token).first()
if token_object:
return token_object.user.username, token_object.token
else:
raise APIException("认证失败") class UserAuthTwo(object):
def authenticate(self, request):
raise APIException("就是这么简单!") class BookView(ModelViewSet):
# 2.指定认证类,固定写法
authentication_classes = [UserAuth, UserAuthTwo]
# 获取数据源, 固定写法
queryset = models.Book.objects.all()
# 序列化类, 固定写法
serializer_class = BookSerializer

全局认证

如果希望所有的数据接口都需要认证怎么办?很简单,如果认证类自己没有 authentication_classes ,就会到 settings 中去找,通过这个机制,我们可以将认证类写入到 settings 文件中即可实现全局认证:

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'authenticator.views.UserAuth',
'authenticator.views.UserAuthTwo',
),
}

权限组件

与认证组件几乎差不多,只要判断该用户的级别,是否给予通过

权限组件的使用

定义权限类

from rest_framework.permissions import BasePermission

class UserPermission(BasePermission):
message = "您没有权限访问该数据"
def has_permission(self, request, view):
# 用户级别是否超过普通用户
if request.user.user_type > 1:
return Truereturn False

同样的逻辑,同样的方式,只是执行权限的方法名与执行认证的方法名不一样而已,名为 has_permission ,并且需要将当前的视图类传递给该方法。

视图类中加入 permission_classes 变量:

class BookView(ModelViewSet):
# 指定认证类,固定写法
authentication_classes = [UserAuth]
# 指定权限类,固定写法
permission_classes = [UserPermission]
# 获取数据源, 固定写法
queryset = models.Book.objects.all()
# 序列化类, 固定写法
serializer_class = BookSerializer

~>.<~

DRF Django REST framework 之 认证组件(五)的更多相关文章

  1. Django REST Framework之认证组件

    什么是认证 认证即需要知道是谁在访问服务器,需要有一个合法身份.认证的方式可以有很多种,例如session+cookie.token等,这里以token为例.如果请求中没有token,我们认为这是未登 ...

  2. DRF Django REST framework 之 视图组件(四)

    引言 在我们有几十上百的视图类,都有get,post等方法,在功能类似时,会导致大量的重复代码出现,显然还有很多可以优化的地方.这也就有了视图组件,它的功能非常强大,能很好的优化接口逻辑. 视图组件 ...

  3. 基于django rest framework做认证组件

    先导入要用到的类 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions ...

  4. 轻轻松松学会 DRF Django REST framework

    据我了解,目前的IT行业的大部分后端开发,都是需要进行前后端分离的,而前后端分类必不可少的是rest 规范,以下是django rest framework的学习路径: DRF Django REST ...

  5. Django Rest framework 之 认证

    django rest framework 官网 django rest framework 之 认证(一) django rest framework 之 权限(二) django rest fra ...

  6. DRF Django REST framework APIView(一)

    什么是REST? REST是一个标准,一种规范,遵循REST风格可以使开发的接口通用,便于调用者理解接口的作用. 使url更容易理解,让增删改清晰易懂,在前后端分离开发中按照这一规范能加快开发效率,减 ...

  7. django rest framework用户认证

    django rest framework用户认证 进入rest framework的Apiview @classmethod def as_view(cls, **initkwargs): &quo ...

  8. DRF Django REST framework 之 频率,响应器与分页器组件(六)

    频率组件 频率组件类似于权限组件,它判断是否给予请求通过.频率指示临时状态,并用于控制客户端可以向API发出的请求的速率. 与权限一样,可以使用多个调节器.API可能会对未经身份验证的请求进行限制,而 ...

  9. drf token刷新配置、认证组件(使用)、权限组件(使用)、频率组件(使用)、异常组件(使用)

    目录 一.特殊路由映射的请求 二.token刷新机制配置(了解) 三.认证组件项目使用:多方式登录 1.urls.py 路由 2.views.py 视图 3.serializers.py 序列化 4. ...

随机推荐

  1. PHP过滤换行的方法

    PHP过滤换行的方法 <pre> public function trimall($str) { $qian = array(" ", " ", & ...

  2. 模拟实现IoC容器

    Spring的IoC核心就是控制反转,将对实现对象的操作控制器交出来,由IoC容器来管理,从配置文件中获取配置信息,Java对XML文档提供了完美的支持,dom4j功能强大,而下面我就用JDOM这一开 ...

  3. Zabbix-(一) 安装与部署

    Zabbix-(一)安装与部署 一.前言 本文记录在Centos7.6平台 通过yum安装部署Zabbix 4.4 准备 Centos7.6 虚拟机一台(ip: 192.168.152.140) My ...

  4. PHP---无限极分类数组处理

    $array = array(    0=>array('id'=>1,'uid'=>0,'menuname'=>'菜单1','url'=>0,'addtime'=> ...

  5. [LC]783题 二叉搜索树结点最小距离(中序遍历)

    ①题目 给定一个二叉搜索树的根结点 root, 返回树中任意两节点的差的最小值. 示例: 输入: root = [4,2,6,1,3,null,null]输出: 1解释:注意,root是树结点对象(T ...

  6. Java枚举——枚举的作用、使用方法、使用场景

    枚举的定义 枚举关键字enum 枚举类是一种特殊类,它和普通类一样可以使用构造器.定义成员变量和方法,也可以实现多个接口,但不能继承类. 枚举的使用 enum Color { RED, BLUE, G ...

  7. nyoj 1022 合纵连横 (并查集<节点删除>)

    合纵连横 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 乱世天下,诸侯割据.每个诸侯王都有一片自己的领土.但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法 ...

  8. React入门知识点清单

    做前端的一定都知道现在是三大框架--Vue.React.Angular三足鼎立的时代.Vue是公认的最容易入门的,因为它文件结构上有传统的HTML的影子,让刚接触它的前端人员刚到很"亲切&q ...

  9. Redis的内存淘汰策略

    Redis占用内存大小 我们知道Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小. 1.通过配置文件配置 ...

  10. three.js使用卷积法实现物体描边效果

    法线延展法 网上使用法线延展法实现物体描边效果的文章比较多,这里不再描述. 但是这种方法有个缺点:当两个面的法线夹角差别较大时,两个面的描边无法完美连接.如下图所示: 卷积法 这里使用另一种方法卷积法 ...