DRF(4) - 认证、权限组件
一、引入
通过前面三节课的学习,我们已经详细了解了DRF提供的几个重要的工具,DRF充分利用了面向对象编程的思想,对Django的View类进行了继承,并封装了其as_view方法和dispatch方法,随后提供了几个非常方便的编程工具,比如解析器、序列化。
我们通过解析器,可以对来自客户端的application/json数据进行解析,另外,通过序列化工具,我们能够快速构建一套符合REST规范的api,随后又通过DRF的mixin、view及viewset对这些接口逻辑进行优化。
有了他们,程序员开发Web应用的效率大大提高了,虽然我们也尝试自己动手实现了这些功能,但是既然有了优秀的工具,我们就不必费尽心思重复发明轮子。DRF并不仅仅提供了这几个工具,今天我们就来继续深入学习DRF提供的一些其他的工具。
跟以往一样,我们不仅仅要学会这些工具的使用方式,并且要深入研究他们的源码,希望大家在研究源码的过程中,能够对面向对象编程的思路有更加深刻的认识。
在编程的世界中,我们认为,用户输入的所有数据都是不可靠的,不合法的,直接使用用户输入的数据是不安全的,接下来,我们要学习认证组件、权限组件、频率组件。
二、认证组件
很久以前,Web站点只是作为浏览文档和其他资源的工具,甚少有什么用户交互之类的烦人的事情需要处理,所以,Web站点的开发这根本不关心什么人在什么时候访问了什么资源,不需要记录任何数据,有客户端请求,我即返回数据,简单方便,每一个http请求都是新的,响应之后立即断开连接。
而如今,不管是论坛类、商城类、社交类、门户类还是其他各类Web站点,大家都非常重视用户交互,只有跟用户交互了,才能进一步留住用户,只有留住了用户,才能知道用户需求,知道了用户需求,就是有商机,有了流量,才能够有钱,有了资金企业才能继续发展,可见,用户交互是非常重要的,甚至可以说是至关重要的一个基础功能。而谈到用户交互,必须要谈到下面介绍的认证、权限和频率。
http协议是无状态的,大家都知道,之前我们学习过使用cookie和session两种方式可以保存用户信息,这两种方式不同的是cookie保存在客户端浏览器中,而session保存在服务器中,他们各有优缺点,配合起来使用,可将重要的敏感的信息存储在session中,而在cookie中可以存储不太敏感的数据。
下面介绍的是使用token的方式,token称之为令牌。cookie、session和token都有其应用场景,没有谁好谁坏,不过我们开发数据接口类的Web应用,目前用token还是比较多的。
token认证的大致步骤是这样的:
- 用户登录,获取用户名密码,查询用户表,如果存在该用户,生成token,否则返回错误信息;
- 更新或者新增token信息;
接下来,我们创建两个model,如下所示(token也可以存储在user表中,不过建议存储在userToken表中):
from django.db import models class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
user_type_entry = (
(1, 'Delux'),
(2, 'SVIP'),
(3, 'VVIP')
)
user_type = models.IntegerField(choices=user_type_entry) def __str__(self):
return self.username class UserToken(models.Model):
token =models.CharField(max_length=128)
user = models.OneToOneField(to='User', on_delete=models.CASCADE)
我们无需实现get方法,因为涉及登录认证,所以写post方法接口,登录都是post请求,登录视图类如下所示:
class UserView(APIView):
def post(self, request): fields = {'username', 'password'}
user_info = dict() if fields.issubset(set(request.data.keys())):
for key in fields:
user_info[key] = request.data[key] user_instance = User.objects.filter(**user_info).first() response = dict()
if user_instance is not None:
access_token = get_token.generater_token() # 检查是否有此记录,有则更新,无则新增
UserToken.objects.update_or_create(user=user_instance, defaults={
"token": access_token
})
response["status_code"] = 200
response["status_message"] = "登录成功"
response["access_token"] = access_token
response["user_role"] = user_instance.get_user_type_display()
else:
response["status_code"] = 201
response["status_message"] = "登录失败,用户名或密码错误" return JsonResponse(response)
简单写了个获取随机字符串的方法用来生成token值,如下:
import uuid
def generater_token():
random_str = ''.join(str(uuid.uuid4()).split('-'))
return random_str
以上就是token的简单生成方式,当然,在生产环境中不会如此简单,关于token也有相关的库,我们构造几条数据之后,可以通过POSTMAN工具来创建几个用户的token信息。
接下来,如何对已经登录成功的用户实现访问授权呢?也就是说,只有登录过的用户(有token值)才能访问特定的数据,该DRF的认证组件出场了。
1、DRF认证组件使用
首先,我们来看一看,DRF认证组件的使用方式,首先,我们必须新建一个认证类,之后的认证逻辑就包含在这个类里面:
from rest_framework.exceptions import AuthenticationFailed
# 定义认证类
class UserAuth(object):
# 固定写法(继承BaseAuthentication的话,authenticate_header可以不写)
def authenticate_header(self, request):
pass def authenticate(self, request):
# 使用postman模拟发送token,所以用request.query_params
user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first()
if token_object:
return token_object.user, token_object.token
else:
raise AuthenticationFailed("认证失败")
实现方式看上去非常简单,到token表里面查看token是否存在,然后根据这个信息,返回对应信息即可,然后,在需要认证通过才能访问的数据接口里面注册认证类即可:
from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet): authentication_classes = [UserAuth] # 指定认证类
queryset = Book.objects.all()
serializer_class = BookSerializer
2、多个认证类的实现
我们还可以指定多个认证类,但是需要注意的是,如果需要返回什么数据,必须在最后一个认证类中返回,因为如果在前面返回,在self._authentication()方法中会对返回值进行判断,如果不为空,认证的过程就会中止,多个认证类的实现方式如下:
class UserAuth(object):
def authenticate_header(self, request):
pass def authenticate(self, request):
raise AuthenticationFailed("认证失败") class UserAuth2(object):
def authenticate_header(self, request):
pass def authenticate(self, request):
user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first()
if token_object:
return token_object.user, token_object.token
else:
raise AuthenticationFailed("认证失败") class BookView(ModelViewSet): authentication_classes = [UserAuth, UserAuth2]
4、如果不希望每次都写那个无用的authenticate_header方法,我们可以这样:
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed class UserAuth2(BaseAuthentication):
def authenticate(self, request):
raise APIException("认证失败") class UserAuth(BaseAuthentication):
def authenticate(self, request):
user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first()
if token_object:
return token_object.user, token_object.token
else:
raise AuthenticationFailed("认证失败")
继承BaseAuthentication类即可
5、全局认证
如果希望所有的数据接口都需要认证怎么办?很简单,关键点就是下面这句源码:
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES
如果认证类自己没有authentication_classes,就会到settings中去找,通过这个机制,我们可以将认证类写入到settings文件中即可实现全局认证:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'authenticator.utils.authentication.UserAuth',
'authenticator.utils.authentication.UserAuth2',
),
}
三、权限组件
1、权限组件使用
1)定义权限类
class UserPerms():
message = '您没有访问权限' # 重写提示信息
# 当url中含有正则时要写has_object_permission方法
def has_object_permission(self, request, view, obj):
return True def has_permission(self, request, view):
if request.user.user_type == 2:
return True
else:
return False
2)同样的逻辑,同样的方式,只是执行权限的方法名与执行认证的方法名不一样而已,名为has_permission,并且需要将当前的视图类传递给该方法。在视图类中加入permission_classes变量:
from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet): authentication_classes = [UserAuth] # 指定认证类
permission_classes = [UserPerms] # 指定权限类 queryset = Book.objects.all()
serializer_class = BookSerializer
四、补充知识点
1、issubset(是否是子集)
fields = {'username', 'password'}
user_data = {'username':'alex', 'password':'', 'hobby':'sing'}
print(fields.issubset(user_data.keys())) # True
2、给属性设置值
class Person(object):
@property
def name(self):
print('getter has been executed')
return self._name @name.setter
def name(self,value):
print('setter has been executed')
self._name = value p1 = Person()
p1.name = 'alex'
print(p1.name)
3、update_or_create
# 检查是否有这条记录,有则更新(需要defaults参数,类型字典),无则新增
UserToken.objects.update_or_create(user=user_obj, defaults={
"token": access_token
})
DRF(4) - 认证、权限组件的更多相关文章
- DRF内置权限组件之自定义权限管理类
DRF内置权限组件permissions 权限控制可以限制用户对于视图的访问和对于具体数据对象的访问. 在执行视图的dispatch()方法前,会先进行视图访问权限的判断 在通过get_object( ...
- Django drf:认证及组件、token、局部钩子源码分析
一.drf认证功能 二.token讲解 三.局部钩子源码分析 一.drf认证功能 1.认证简介: 只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录则不能查 ...
- 9) drf JWT 认证 签发与校验token 多方式登陆 自定义认证规则反爬 admin密文显示
一 .认证方法比较 1.认证规则图 django 前后端不分离 csrf认证 drf 前后端分离 禁用csrf 2. 认证规则演变图 数据库session认证:低效 缓存认证:高效 jwt认证:高效 ...
- DRF之版本控制、认证和权限组件
一.版本控制组件 1.为什么要使用版本控制 首先我们开发项目是有多个版本的当我们项目越来越更新,版本就越来越多,我们不可能新的版本出了,以前旧的版本就不进行维护了像bootstrap有2.3.4版本的 ...
- DRF之权限认证频率组件
概要 retrieve方法源码剖析 认证组件的使用方式及源码剖析 权限组件的使用方式及源码剖析 频率组件的使用方式及源码剖析 知识点复习回顾 Python逻辑运算 知识点复习回顾一:Python逻辑运 ...
- DRF框架(六)——三大认证组件之认证组件、权限组件
drf认证组件 用户信息表 from django.db import models from django.contrib.auth.models import AbstractUser class ...
- Django框架深入了解_03(DRF之认证组件、权限组件、频率组件、token)
一.认证组件 使用方法: ①写一个认证类,新建文件:my_examine.py # 导入需要继承的基类BaseAuthentication from rest_framework.authentica ...
- drf框架 - 三大认证组件 | 认证组件 | 权限组件 | 频率组件
RBAC 基于用户权限访问控制的认证 - Role-Based Access Control Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为 三表规则.五表规则,Django采用 ...
- drf:restful概念,类继承关系,drf请求封装,drf请求流程,版本控制组件,认证组件(token),权限组件
1.restful规范 resfful规范的概念最重要: 是一套规范,规则,用于程序之间进行数据交换的约定. 他规定了一些协议,对我们感受最直接的就是,以前写增删改查的时候需要些四个视图寒素,rest ...
随机推荐
- 安装好Oracle和PLSQLDeveloper后,PLSQLDeveloper登录时没有可选数据库和连接为问题
1.登录PL/SQL Developer 这里省略Oracle数据库和PL/SQL Developer的安装步骤,注意在安装PL/SQL Developer软件时,不要安装在Program Files ...
- emblog后台拿shell
emlog版本:5.3.1 先本地弄好shell 新建一个文件夹,里面放shell,shell名称和文件名要一致.压缩为zip 然后在安装插件处上传. 成功后的路径content/plugins/te ...
- STM32F10x_模拟I2C读写EEPROM
Ⅰ.写在前面 说到IIC,大家都应该不会陌生,我们初学单片机的时候或多或少都知道或了解过,甚至使用I2C控制过器件.但是,有多少人真正去深入理解,或者深入研究过I2C通信协议呢? 1.我们有必要学习I ...
- 大数据(7) - zookeeper的安装与使用
简介 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...
- chpasswd 更简单的更改密码的方式
[root@m01 .ssh]# useradd test[root@m01 .ssh]# echo "test:123"|chpasswd Linux命令:chpasswd 批量 ...
- ajax取消重复请求
var pendingRequests = {}; $.ajaxPrefilter(function(options, originalOptions, jqXHR) { var key = opti ...
- BootStrap带样式打印
在新窗口打印时bootstrap表格的样式出不来,因为打印时没有加载CSS样式. 我在jquery.PrintArea.js的基础上改造了下打印的方法: (function ($) { var pri ...
- [转]软件测试- 3 - Mock 和Stub的区别
由于一直没有完全搞明白Mock和Stub的区别,所以查了很多文章,而这一篇是做好的: http://yuan.iteye.com/blog/470418 尤其是8楼,Frostred的发言,描述地相当 ...
- Jafka Broker代码阅读之总览
从本文开始,笔者将尝试从源码角度解读Jafka(Kafka)的特性,探究其背后的实现原理与技术.前面讲解Jafka Broker的文章中有提到下面这段启动服务端的代码,我们就从这里开始. Proper ...
- django 之 常用命令
Django 基本命令 本节主要是为了让您了解一些django最基本的命令,请尝试着记住它们,并且多多练习下 1. 新建一个 django project django-admin.py startp ...