drf之登录功能,认证组件,权限组件,频率组件
一、登录功能
表模型
class UserInfo(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
class UserToken(models.Model):
token = models.CharField(max_length=64)
user = models.OneToOneField(to=UserInfo, on_delete=models.CASCADE)
视图类
#### 登录接口
from rest_framework.views import APIView
from .models import *
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
import uuid
class UserView(ViewSet):
def login(self,request):
username = request.data.get('name')
password = request.data.get('password')
user = UserInfo.objects.filter(name=username, password=password).first()
if user:
token = str(uuid.uuid4())
# 复杂写法
# res = UserToken.objects.filter(user_id=user.id)
# if res:
# UserToken.objects.update(token=token)
# return Response({'code': 100, 'msg': '登录成功', 'token': token})
# else:
# UserToken.objects.create(user_id=user.id,token=token)
# return Response({'code':100, 'msg': '登录成功', 'token': token})
# 把token存到表中,UserToken表有值就更新,没有值就新增
UserToken.objects.update_or_create(user=user, defaults={'token':token})
return Response(({'code':100, 'msg': '登录成功', 'token': token}))
else:
return Response({'code': 101, 'msg': '用户名或密码错误'})
回顾
UserToken表中有user字段
拿到了一个UserToken表的对象
user_token.token 就是字符串
user_token.user 基于对象的跨表查询,拿到的是user对象 user_token.user.password
user_token.user_id 隐藏了这个字段,是可以用的,它是管理的user对象的id号
查询功能
UserToken.objects.filter(user=user对象)
UserToken.objects.filter(user_id=user.id)
路由
from django.contrib import admin
from django.urls import path
from app01 import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('user', views.UserView, 'user') # 第一个参数是前缀,第二个是视图类,第三个参数是个别名必须要写
urlpatterns = [
path('admin/', admin.site.urls),
# path('login/', views.UserView.as_view({'post':'login'}))
]
urlpatterns += router.urls
postman
二、认证组件
APIView执行流程
-在视图视图类的方法之前,执行了三大认证
-认证
认证:登录认证
-登录认证---》控制,某个接口必须登录后才能访问
认证组件使用步骤(固定用法)
- 新建一个auth文件,写一个类,继承BaseAuthentication
- 在类中写:authenticate
- 在方法中,完成登录认证,如果 不是登录的,抛异常
- 如果是登录的,返回登录用户和token
from rest_framework.authentication import BaseAuthentication
from .models import UserToken
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self, request): # 父类中有,一定要重写
# 校验用户是否登录---》请求中携带我给的token,就是登录了
# token在哪携带,是接口规定的---》
# 1 规定带在请求地址中---》讲这个
# 2 规定带在请求头中(这个多)
# 3 规定待在请求体中
# 取出token META HTTP_TOKEN
token = request.query_params.get('token')
# 去数据库中,根据token,校验有没有数据
user_token = UserToken.objects.filter(token=token).first()
if user_token:
user = user_token.user # 当前登录用户就是user
return user, token
else:
# 说明它带的token不对的
raise AuthenticationFailed('您没有登录,不能访问')
- 在视图类中,使用认证类(局部使用)
class BookView(APIView):
authentication_classes = [LoginAuth, ]
- 全局使用:
# 全局使用
### 重点:不要在配置文件中,导入莫名其妙的包
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'app01.auth.LoginAuth'
],
}
- 全局使用后,局部禁用
class UserView(ViewSet):
# 局部禁用
authentication_classes = []
- 认证类的使用顺序
-
-优先用视图类配置的
-
-其次用项目配置文件
-
-最后用drf默认的配置
重点;一旦通过认证,在request中就有当前登录用户
def get(self, request):
# 一旦通过认证,在request中就有当前登录用户
print(request.user.name,'访问了接口')
先登录
然后再拿token去查books
三、权限组件
大家都登录了,但有的功能(接口),只有超级管理员能做,有的功能所有登录用户都能做----》这就涉及到权限的设计了
ps:权限设计:比较复杂---》有acl,rbac,abac。。。
咱们现在只是为了先讲明白,drf的权限组件如何用,咱们先以最简单的为例
-查询所有图书:所有登录用户都能访问(普通用户和超级管理员)
-其实没有权限控制
-删除图书,只有超级管理员能访问
-给其它用户设置的权限
在modles中用户表加一个字段判断是否为超级管理员
class UserInfo(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
user_type = models.IntegerField(choices=((1, '超级管理员'), (2, '普通登录用户'), (3, '2B用户')),default=3)
权限类的使用步骤
1 建一个permission文件夹,写一个类,继承BasePermission
2 在类中写方法:has_permission
-如果有权限,就返回True
-如果没有权限,就返回False
-错误信息是self.message='字符串'
from rest_framework.permissions import BasePermission
class AdminPermission(BasePermission):
def has_permission(self, request, view):
# 如果有权限,就是返回True,没有权限,返回False
# 判断user_type是不是 1,根据当前登录用户
# request.user # 就是当前登录用户,一旦来到这里,认证就通过了
if request.user.user_type == 1: # 一定要注意类型#####
return True
else:
# 错误信息
self.message = '您好:%s,您没有权限' % request.user.name
return False
3 局部使用
class BookDetailView(APIView):
permission_classes = [AdminPermission, ]
4 全局使用
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'app01.permission.AdminPermission'
],
}
5 局部禁用
class BookView(APIView):
permission_classes = []
四、频率组件
限制访问频次
-比如某个接口,一分钟只能访问5次,超过了就得等
-按IP地址 限制
-按用户id 限制
频率类的使用步骤
1 新建一个throttling文件,写个类,继承:SimpleRateThrottle
2 重写某个方法:get_cache_key
-可以返回ip或用户id
-返回什么,就以什么做频率限制
3 写一个类属性,随意命名一个名
scope = 'lqz'
from rest_framework.throttling import SimpleRateThrottle
class ThreeThrottle(SimpleRateThrottle):
scope = 'iu'
def get_cache_key(self, request, view):
ip = request.META.get('REMOTE_ADDR')
print('客户端的IP是:',ip)
return ip
4 在配置文件中配置:
'DEFAULT_THROTTLE_RATES': {
'lqz': '3/m' # 一分钟访问3次
},
5 全局用
'DEFAULT_THROTTLE_CLASSES': [
],
6 局部用
class BookView(APIView):
throttle_classes = [MyThrottle]