drf—— 编写登录接口,用同一个接口既可以不登录访问,又可以登录访问
要求:
编写登录接口,一个接口既可以不登录访问,又可以登录访问(匿名用户一分钟访问1次,登录用户一分钟访问3次) #需要用到student和user表
1.models.py
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=32)
sex = models.SmallIntegerField(choices=((1, '男'), (2, '女'), (3, '未知')), default=1)
age = models.IntegerField()
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
user_type = models.IntegerField(choices=((1, '超级用户'), (2, '普通用户'), (3, '二笔用户')),default=1)
#此表完全可以与User表合为一个,但这样解耦合,可扩展性高
class UserToken(models.Model):
user = models.OneToOneField(to='User',on_delete=models.CASCADE)
token = models.CharField(max_length=64)
2.数据迁移,两条命令;然后连接数据库,在user和student表中写入测试数据
3.serializer.py
from rest_framework import serializers
from app01.models import Student
class StudentSerializer(serializers.ModelSerializer):
sex = serializers.CharField(source='get_sex_display')
class Meta:
model = Student
fields = '__all__'
4.auth.py
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
from app01 import models
#from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
token = request.GET.get('token')
res = models.UserToken.objects.filter(token=token).first()
if res:
return (res.user, token)
else:
return None
class MySimpleThrottle(SimpleRateThrottle):
scope = 'xxx'
def get_cache_key(self, request, view):
if not request.user.id: # 没有登录用户
return self.get_ident(request) # 根据ip限制
else:
return None
class MyLoginThrottle(SimpleRateThrottle):
scope = 'login'
def get_cache_key(self, request, view):
return request.user.pk
5.views.py
from rest_framework.views import APIView
from app01 import models
import uuid
from app01.auth import LoginAuth,MyLoginThrottle,MySimpleThrottle
class LoginView(APIView):
authentication_classes = []
def post(self, request):
res = {'code': 100, 'msg': '登录成功'}
username = request.data.get('username')
password = request.data.get('password')
# 查询数据库
user = models.User.objects.filter(username=username, password=password).first()
if user:
token = uuid.uuid4() # 生成一个随机字符串
# 把token存到UserToken表中(如果是第一次登录:新增,如果不是第一次:更新)
models.UserToken.objects.update_or_create(defaults={'token': token}, user=user)
res['token'] = token
return Response(res)
else:
res['code'] = 101
res['msg'] = '用户名或密码错误'
return Response(res)
from app01.models import Student
from app01.serializer import StudentSerializer
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework.mixins import CreateModelMixin
class StudentView(GenericViewSet, ListModelMixin, CreateModelMixin):
queryset = Student.objects.all()
serializer_class = StudentSerializer
authentication_classes = [LoginAuth,]
throttle_classes = [MyLoginThrottle,MySimpleThrottle,]
6.urls.py
from django.urls import path
from app01 import views
#自动生成路由
from rest_framework.routers import SimpleRouter
router=SimpleRouter()
router.register('students',views.StudentView)
urlpatterns = [
path('login/', views.LoginView.as_view()),
]
urlpatterns+=router.urls
print(router.urls)
7.settings.py
INSTALLED_APPS = [
...
'rest_framework'
]
REST_FRAMEWORK = {
# 'DEFAULT_THROTTLE_CLASSES':['app01.auth.MyThrottle',],
'DEFAULT_THROTTLE_RATES' : {
'xxx':'1/m',
'login':'3/m'
}
}
后续:
如果要写两个接口,一个接口不登陆访问1次,一个接口登录访问3次,可以用以下的方式:(推荐使用写两个接口,这样解耦合,不需要写那么多判断麻烦)
-方式一:
-写两个频率类(一个是根据ip限制,另一个根据userid)
-方式二:
-使用内置的,如果可以,就没问题就可以,如果又问题需要继承重写get_cache_key方法
赞 (0)
