三大认证组件
登录认证
我们可以使用auth自带的User表,也可以选择自定义表.
写登录接口,登录成功要有标志,生成一个随机的字符串,放到表中,以后只要携带这个字符串就可以登录成功。
视图层
方法一:
class UserView(GenericViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
def login(self, request, *args, **kwargs):
# 获取从前端传入的数据,并进行数据校验判断该用户是否存在,拿到的是QuerySet对象
user_obj = self.get_queryset().filter(username=request.data.get("username"),password=request.data.get("password"))
print(user_obj[0])
# 判断用户是否存在
if user_obj:
# 存在获取一个UUID
token = str(uuid.uuid4())
# 通过用户对象查询Token表中是否存在一个Token对象,返回None或者一个对象
user_taken = models.Token.objects.filter(usertoken=user_obj[0]).first()
print(token, "++++++++") # c03d3613-d4b7-4c17-abf6-eb82809fcfee ++++++++
print(user_taken, "----------") # Token object (1) ----------
# 判断这个Token对象是否存在
if user_taken:
# 如果存在将得到的UUID的对象值赋值给Token表中的Token字段,后续可以使用这个字段开登录
models.Token.token = token
# 保存
user_taken.save()
else:
# 如果这个Token对象不存在则给它添加一个
models.Token.objects.create(token=token, usertoken_id=user_obj[0].pk)
return Response({"code": 100, "msg": "登录成功", "username": user_obj[0].username, "token": token})
else:
return Response({"code": 101})
方法二:
使用UserToken.objects.update_or_create(defaults={'token': token}, user=user)
class UserView(GenericViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
def login(self, request, *args, **kwargs):
# 获取从前端传入的数据,并进行数据校验判断该用户是否存在,拿到的是QuerySet对象
user_obj = self.get_queryset().filter(username=request.data.get("username"),password=request.data.get("password"))
print(user_obj[0])
# 判断用户是否存在
if user_obj:
# 存在获取一个UUID
token = str(uuid.uuid4())
Token.objects.update_or_create(defaults={"token": token}, usertoken=user_obj[0])
return Response({"code": 100, "msg": "登录成功", "username": user_obj[0].username, "token": token})
else:
return Response({"code": 101, "msg": "账号或密码错误,请重新输入"})
路由层
urlpatterns = [
path('register/', views.UserView.as_view({"post": "register"})),
path('login/', views.UserView.as_view({"post": "login"})),
认证组件
认证的的作用:
有些接口需要登陆以后才可以访问,没有登录的话就不能访问
登录的接口就是为了限制某些接口的
认证类的使用:
1、导入模块:from rest_framework.authentication import BaseAuthentication
2、重写里面的 def authenticate(self, request):方法
3、在authenticate中完成登录的认证,如果登录成功返回两个值,如果没登录抛出异常
4、在视图类中局部使用
如果已经登录成功,可以在视图类中通过request.user拿到当前登录用户
使用方法
auth.py
1、新建一个auth.py文件用来专门做认证
2、在auth文件中写一个CBV继承BaseAuthentication,在里面重写def authenticate(self, request):方法
from rest_framework.authentication import BaseAuthentication
from .models import UserToken
from rest_framework.exceptions import AuthenticationFailed
class AuthUser(BaseAuthentication):
def authenticate(self, request):
# 获取从前端传入的token值
token = request.GET.get("token")
# 根据获得的token值查token表
token_obj = UserToken.objects.filter(token=token).first()
# 如果存在返回用户名以及token值
if token_obj:
return token_obj.user, token
# 否则抛出异常
else:
raise AuthenticationFailed("您还没有登录")
视图层
from rest_framework.viewsets import ViewSet
from .models import User, UserToken
from rest_framework.response import Response
from rest_framework.decorators import action
from .auth import AuthUser
import uuid
# Create your views here.
class UserView(ViewSet):
@action(methods=["POST"], detail=False)
def login(self, request, *args, **kwargs):
username = request.data.get("username")
password = request.data.get("password")
user = User.objects.filter(username=username, password=password).first()
print(user)
if user:
token = str(uuid.uuid4())
UserToken.objects.update_or_create(defaults={"token": token}, user=user)
return Response({"code": 100, "msg": "登录成功", "username": user.username, "token": token})
else:
return Response({"code": 101, "msg": "登录失败"})
class PublishView(ViewSet):
# 如果想要访问此视图函数必须先登录认证
authentication_classes = [AuthUser]
def list(self, request):
return Response("hhhh")
路由层
from django.contrib import admin
from django.urls import path, include
from app_one.views import UserView, PublishView
from rest_framework.routers import SimpleRouter
render = SimpleRouter()
render.register("user", UserView, "user")
render.register("publish", PublishView, "publish")
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(render.urls)),
]
小结
1、先写好认证类
-局部使用------>配置在视图类中:authentication_classes = [AuthUser]
-全局使用:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'app01.auth.LoginAuth'
],
}
-局部禁用------>在视图类中配置:authentication_classes = []
写认证类:
-一定要重写authenticate方法,否则会抛异常,必须要返回两个参数:当前登录用户user_token.user,用户的 token
-认证类返回的第一个参数---->request.user
-认证类返回的第二个参数---->request.auth
-认证失败主动抛出异常抛AuthenticationFailed,会被drf捕捉到并做处理,不会在前端报错
-前端传入的token值从哪里取?
-在url中:request.GET()/request.query_params.get()
-请求头:request.META.get('HTTP_TOKEN')属性来获取请求头中的数据
-请求体:request.data
权限组件
在系统中:有超级用户、有普通用户、有管理员用户,他们都登陆过了,有分权限,就像普通用户只能访问部分功能, 超级管理员则是可以访问全部功能
使用步骤
from rest_framework.permissions import BasePermission
1、写一个类,继承BasePermission
2、重写has_permission
3、在方法中校验用户是否有权限,如果有,就返回True,如果没有,就返回False
-由于它的执行是在认证之后,所有从request.user中取出当前等用户,判断权限
4、局部使用,在视图类中----->permission_classes = [Permissions]
5、全局使用,在配置文件中:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'app01.auth.LoginAuth'
],
'DEFAULT_PERMISSION_CLASSES': [
'app01.permissions.Permissions',
],
}
permission类
from rest_framework.permissions import BasePermission
1 写一个类,继承 BasePermission
2 重写 has_permission
3 在方法中校验用户是否有权限,如果有,就返回True,如果没有,就返回False
class Permissions(BasePermission):
def has_permission(self, request, view):
# request 当次请求的request, 新的,它是在认证类之后执行的,如果认证通过了request.user 就是当前登录用户
# 拿到当前登录用户,查看它的类型,确定有没有权限
print(request.__dict__)
if request.user.user_type == 3:
return True
else:
self.message = "您的用户类型是%s,您没有权限访问该功能" % (request.user.get_user_type_display())
return False
视图类
class PublishView(ViewSet):
# 如果未登录无法访问该接口
authentication_classes = [AuthUser]
# 如果权限不够无法访问该接口
permission_classes = [Permissions]
def list(self, request):
return Response("hhhh")
路由类
from rest_framework.routers import SimpleRouter
render = SimpleRouter()
render.register("user", UserView, "user")
render.register("publish", PublishView, "publish")
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(render.urls)),
]
Django项目国际化
# 配置文件中--->以后所有英文都会转成中文
INSTALLED_APPS = [
'rest_framework'
]
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
频率组件
作用:
控制一个接口的访问频次,譬如每分钟只可以访问一次等等
对接口进行访问次数限制
使用步骤:
1、写一个类继承SimpleRateThrottle
2、重写get_cache_key,返回什么,就以什么做限制:
-IP地址
-用户id限制
3、写一个类属性:
scope = 'XXX'
4、在配置文件中进行配置:
'''
'DEFAULT_THROTTLE_RATES': {
'drf_day08': '3/m', # 一分钟访问三次 5/s,m,h,d,/秒/分/时/天
},
'''
5、局部使用、全局使用,局部禁用:
-局部使用:throttle_classes = [IPRateThrottle]
-全局使用:
'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.IPRateThrottle'],
throttle
from rest_framework.throttling import SimpleRateThrottle
class IPRateThrottle(SimpleRateThrottle):
# 必须要自定义一个属性,值可以任意命名
scope = "Wayyy"
# 重写get_cache_key方法
def get_cache_key(self, request, view):
return request.META.get("REMOTE_ADDR")
配置文件中配置
'DEFAULT_THROTTLE_RATES': {
'Wayyy': '3/m', # 一分钟访问三次
},
视图文件
class PublishView(ViewSet):
# 如果未登录无法访问该接口
authentication_classes = [AuthUser]
# 如果权限不够无法访问该接口
permission_classes = [Permissions]
throttle_classes = [IPRateThrottle]
def list(self, request):
return Response("hhhh")
排序
什么时候用?
涉及到查询所有数据的时候
# 使用步骤
-1 必须写在继承:GenericAPIView 类的视图类中才行
-2 配置类属性:
filter_backends = [OrderingFilter]
ordering_fields=['id','user_type'] #可以排序的字段
-3 使用
http://127.0.0.1:8000/user/?ordering=user_type #用户类型升序排
http://127.0.0.1:8000/user/?ordering=-user_type #用户类型降序排
http://127.0.0.1:8000/user/?ordering=user_type,-id#先按用户类型升序排,如果用户类型一样,再按id降序排