登录认证
创建用户表
# 用户表
class User(models.Model):
name = models.CharField(max_length=32)
pswd = models.CharField(max_length=32)
vip = models.IntegerField(choices=((0, '普通用户'),(1, 'VIP用户'),(2, 'SIV用户'), (3, '超级管理员')))
is_delete = models.IntegerField(choices=((0, 'Active'), (1, 'Inactive')))
# 令牌表
class Token(models.Model):
token = models.CharField(max_length=64)
user = models.OneToOneField(to=User, on_delete=models.CASCADE)
创建视图层
需要注意的是指令的创建和添加
import uuid
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, ViewSet
from rest_framework.response import Response
from rest_framework.decorators import action
from app01.models import User, Token
# Create your views here.
'''
需求:
---1. 路由想要自动生成
---2. 是否需要序列化
---3.
'''
class UserView(ViewSet):
@action(methods=['POST'], detail=False)
def login(self, request, *args, **kwargs):
# 接收前端传入的数据
name = request.data.get('name')
pswd = request.data.get('pswd')
user = User.objects.filter(name=name, pswd=pswd).first()
# 如果用户存在
if user:
token = str(uuid.uuid4())
user_token = Token.objects.filter(user=user).first()
# if user_token:
# user_token.token = token
# user_token.save()
# else:
# Token.objects.create(user=user, token=token)
# 新用法
Token.objects.update_or_create(defaults={'token':token}, user=user)
return Response({'code':200, 'msg':'登录成功!', 'token':token, '用户名':name})
else:
return Response({'code':1001, 'msg':'用户名或者密码错误'})
第二种方法:
class UserView(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
@action(methods=['POST'], detail=False, url_path='login')
def login(self, request, *args, **kwargs):
user = self.get_queryset().filter(name=request.data.get('name'), pswd=request.data.get('pswd')).first()
if user:
token = str(uuid.uuid4())
Token.objects.update_or_create(defaults={'token':token}, user=user)
return Response({'code':200, 'msg':'登录成功!', 'token':token, '用户名':request.data.get('name')})
else:
return Response({'code':1001, 'msg':'用户名或者密码错误'})
update_or_create 源码
deafult是详情(字典类型), **kwargs是字段
def update_or_create(self, defaults=None, **kwargs):
"""
Look up an object with the given kwargs, updating one with defaults
if it exists, otherwise create a new one.
Return a tuple (object, created), where created is a boolean
specifying whether an object was created.
"""
defaults = defaults or {}
self._for_write = True
with transaction.atomic(using=self.db):
# Lock the row so that a concurrent update is blocked until
# update_or_create() has performed its save.
obj, created = self.select_for_update().get_or_create(defaults, **kwargs)
if created:
return obj, created
for k, v in resolve_callables(defaults):
setattr(obj, k, v)
obj.save(using=self.db)
return obj, False
认证组件
认证有什么作用
给一些接口添加认证。限制登录访问,登录后可以访问,没有登录不可以访问
具体操作步骤
当前举例实在请求地址中添加的token
- 写一个类,继承BaseAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import Token
- 类中重写authenticate
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 通过token校验,在请求地址中拿到token
token = request.query_params.get('token')
# token = request.META.get("HTTP_AUTHORIZATION")
print(token)
user_token = Token.objects.filter(token=token).first()
if user_token:
return Token.user, token
else:
raise AuthenticationFailed('用户没有登录')
-
在authenticate中完成登录认证,如果登录了返回两个值,如果没有登录抛异常
-
在视图类中配合使用
class BookView(ModelViewSet):
authentication_classes = [LoginAuth]
def list(self, request):
print(request.query_params.get('token'))
# print(request.META.get("HTTP_AUTHORIZATION"))
return Response('ok')
如果登录了,可以拿到登录的用户信息,因为我们在auth.py里面return出去了user
其他添加token的办法
Express: var token = req.header("Authorization").split(" ")[1];
Django: token = request.META.get("HTTP_AUTHORIZATION")
Flas: token = request.headers.get("Authorization")
配置文件中的全局配置
在setting.py里面
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':[
'app01.auth.LoginAuth'
],
}
权限组件
目的
系统中有普通用户,VIP用户,SVIP用户,超级管理员。这些用户都登录了,但是要给他们分权限,有的人有权限,有的人可以访问这个接口。没有权限就不能访问。这样的话,我们首先就要在我们的user表里面添加一个字段(用户等级)
代码
from rest_framework.permissions import BasePermission
'''
1. 写一个类,继承BasePermission
2. 重写has_permission
3. 在方法中校验用户是否有权限,如果有,就返回True,如果没有就抛异常
'''
class UserPerimission(BasePermission):
def has_permission(self, request, view):
# request 是当次请求的request(新的,同样也是在认证后执行的)如果认证通过了,request.user就是当前登录用户
# 拿到当前登录用户,查看它的类型,确实有没有权限
print(request.user)
if request.user.vip == 3:
return True
else:
return False
配置文件中的全局配置
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.UserPerimission',],
}
频率组件
目的
控制一个接口的访问频次,比如一分钟只能访问一次。我们为了预防爬虫和其他对程序的损害,我们应该对所有接口都有频率限制。
代码
from rest_framework.throttling import SimpleRateThrottle
'''
1. 写一个类,继承SimpleRateThrottle
2. 重写get_cache_key,返回什么就以什么做限制:IP地址,用户id限制
3. 写一个类属性 scope = ' '
4. 配置文件中配置
'''
class IPRateThrottle(SimpleRateThrottle):
scope = 'HW0906' # 写一个类属性
def get_cache_key(self, request, view):
print(request.user.name)
# 返回IP,以IP地址做限制
# print(request.META)
# return request.META.get('REMOTE_ADDR')
return request.user.name
全局配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.auth.LoginAuth'],
'DEFAULT_PERMISSION_CLASSES': ['app01.permissions.UserPerimission',],
'DEFAULT_THROTTLE_RATES': {'HW0906':'3/m'}, # 一分钟访问3次
'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.IPRateThrottle'],
}