一、认证组件
1.使用
# 模型层
class User(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
class UserToken(models.Model):
user = models.OneToOneField(to='User')
token = models.CharField(max_length=64)
#myAuth.py
from app01 import models
from rest_framework.exceptions import APIException
from rest_framework.authentication import BaseAuthentication
class Auth(BaseAuthentication):
def authenticate(self,request):
# 包装后的request对象,请求来的所有东西都能拿出来
token = request.GET.get('token')
ret = models.UserToken.objects.filter(token=token).first()
# 如果有值,说明登录过了,而且带的随机字符串也是正确的
# 如果认证通过,需要返回东西,如果认证不通过,要抛异常
if ret:
# 返回一个元组如果返回None,就会是一个匿名用户
return ret.user,ret
else:
# 如果没有值,抛异常
raise APIException('您没有登录')
from app01.mySer import *
import uuid
# 登陆视图
class Login(APIView):
def post(self, request):
response = {'status': 200, 'msg': '登录成功'}
name = request.data.get('name')
pwd = request.data.get('pwd')
user = models.User.objects.filter(name=name, pwd=pwd).first()
if user:
token = uuid.uuid4()
# 登陆成功后,存入token表
models.UserToken.objects.create(token=token, user=user)
response['token'] = token
else:
response['status'] = 201
response['msg'] = '添加失败'
return JsonResponse(response, safe=False)
# 局部使用,在所需的视图里局部使用
class Books(APIView):
# 登录后才能操作
authentication_classes=[Auth,]
def get(self, request):
.......
def post(self, request):
.......
class BooksDetail(APIView):
authentication_classes = [Auth, ]
def get(self, request):
.......
def post(self, request):
.......
# 全局使用
# setting.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['app01.my_Auth.Auth']
}
# 全局使用后局部禁用
# 在所属的试图里写一个空
authentication_classes=[]
2.源码分析
# 第一步
# APIView类
def dispatch(self, request, *args, **kwargs):
........
# 重点是这个,这是认证、频率相关的
self.initial(request, *args, **kwargs)
........
# 第二步
# APIView类
def initial(self, request, *args, **kwargs):
........
# 这个就是认证
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
# 第三步
# APIView类
def perform_authentication(self, request):
# 这个request是已经封装好后的Request的对象
request.user
# 第四步
# Request类
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
# 第五步
# Request类
def _authenticate(self):
# 从下面回到这里,就可以知道
# self.authenticators=authentication_classes
# 拿上面的例子举例
# self.authenticators=[Auth, ];authenticator就是Auth
for authenticator in self.authenticators:
try:
# 注意:authenticator.authenticate(self)中的self,由于是在Request类里,所以这个self就是Request实例化的对象request;
# 所以:authenticator.authenticate(self)=Auth.authenticate(self,request)
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
# user_auth_tuple:authenticator.authenticate(self)的返回值,是个元组
# 这就是一个元组的解压
# self.user:request.user
# self.auth:request.auth
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
# self.authenticators的来历
# APIView类
# self.authenticators 是Request实例化的时候传进来的参数self.get_authenticators()
def initialize_request(self, request, *args, **kwargs):
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
# self.get_authenticators()的来历
# APIView类
def get_authenticators(self):
# self.authentication_classes
# 从子类找验证类:authentication_classes = [Auth, ]
# 从父类APIView里找验证类:authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
# 找到之后,循环并加上()执行
return [auth() for auth in self.authentication_classes]
3.不依靠数据库的token验证
import hashlib
# 设置token
def set_token(id, salt='1'):
md5 = hashlib.md5()
md5.update(str(id).encode('utf-8'))
md5.update(salt.encode('utf-8'))
return md5.hexdigest() + '|' + str(id)
# 校验token
def check_token(token, salt='1'):
tk = token.split('|')
md5 = hashlib.md5()
md5.update(str(tk[-1]).encode('utf-8'))
md5.update(salt.encode('utf-8'))
if tk[0] == md5.hexdigest():
return True
else:
return False
class Auth(BaseAuthentication):
def authenticate(self, request):
token = request.GET.get('token')
# 如果GET里没有token,check_token里的split方法就会报错
# 所以这里try一下异常
try:
ret = common.check_token(token)
if ret:
return
else:
# 抛异常
raise
except Exception as e:
raise AuthenticationFailed('认证失败')
class Login(APIView):
def post(self, request):
response = {'status': 100, 'msg': '登陆成功', 'token': None}
name = request.data.get('name')
pwd = request.data.get('pwd')
user = models.User.objects.filter(name=name, pwd=pwd).first()
if user:
# 传入用户id获得对应的token
token = common.set_token(user.pk)
response['token'] = token
else:
response['status'] = 200
response['msg'] = '登录失败'
return JsonResponse(response, safe=False)
class Book(APIView):
authentication_classes = [myAuthentication.Auth, ]
def get(self, request):
response = {'status': 100, 'msg': '查看成功', 'data': None}
books = models.Book.objects.all()
ret = mySerializers.BookSerializers(books,many=True)
response['data']=ret.data
return JsonResponse(response,safe=False)
4.顺序
认证类使用顺序:先用视图类中的验证类,再用settings里配置的验证类,最后用默认的验证类
二、权限组件
1.简单使用
from rest_framework.permissions import BasePermission
class VipPermission(BasePermission):
message = '不是会员,查看不了'
def has_permission(self, request, view):
user_type = request.user.user_type
if user_type == '1':
return True
else:
return False
class Book(APIView):
# 局部使用
permission_classes = [myPermission.VipPermission, ]
def get(self, request):
response = {'status': 100, 'msg': '查看成功', 'data': None}
books = models.Book.objects.all()
ret = mySerializers.BookSerializers(books, many=True)
response['data'] = ret.data
return JsonResponse(response, safe=False)
# 全局使用
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':['app01.myPermission.VipPermission']
}
# 全局使用中局部禁用
class Book(APIView):
permission_classes = []
2.源码分析
# 第一步
# APIView类
def dispatch(self, request, *args, **kwargs):
........
# 重点是这个,这是认证、频率以及权限相关的
self.initial(request, *args, **kwargs)
........
# 第二步
# APIView类
def initial(self, request, *args, **kwargs):
........
self.perform_authentication(request)
# 这就是 权限方法
self.check_permissions(request)
self.check_throttles(request)
# 第三步
# APIView类
def check_permissions(self, request):
# 这里的原理与认证类一致
for permission in self.get_permissions():
# 有一点不同的是has_permission(request, self)中的self是APIView的self
if not permission.has_permission(request, self):
self.permission_denied(request, message=getattr(permission, 'message', None)
)
# self.get_permissions()的来历
def get_permissions(self):
return [permission() for permission in self.permission_classes]
3.顺序
权限类使用顺序:先用视图类中的权限类,再用settings里配置的权限类,最后用默认的权限类