一 认证简介:
只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录,就不能查看,这时候需要用到认证组件
二 局部使用
models.py
class User(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=64) user_type=models.IntegerField(choices=((1,"超级管理员"),(2,"普通管理员"),(3,"2b用户")),default=3) #跟User表做一对一关联 class Token(models.Model): user=models.OneToOneField(to='User') token = models.CharField(max_length=64)
新建认证类(验证通过return两个参数)
rom rest_framework.authentication import BaseAuthentication from app01 import models from rest_framework.exceptions import AuthenticationFailed from rest_framework.permissions import BasePermission class MyAuth(BaseAuthentication): def authenticate(self,request): #写一些认证的逻辑 # print('我是认证类中的方法,只要配置了,一定会走我') token=request.GET.get('token') token_obj=models.Token.objects.filter(token=token).first() if token_obj: #有值表示登录了 #token_obj.user 当前登录的user对象 return token_obj.user,token_obj else: #没有值,表示没有登录,抛异常 raise AuthenticationFailed('您没有登录')
class MyPermision(BasePermission):
message = '不是超级用户,查看不了'
def has_permission(self,request,view):
if request.user.user_type==1:
return True
else:
return False
view层:
from django.shortcuts import render,HttpResponse # Create your views here. from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request from django.core.exceptions import ObjectDoesNotExist from app01 import models from rest_framework.exceptions import AuthenticationFailed import uuid from rest_framework.authentication import BaseAuthentication from app01.MyAuths import MyAuth,MyPermision #用户必须登录之后才能访问获取所有图书接口 class Books(APIView): #可以写多个认证类 # authentication_classes=[MyAuth,] #只有超级用户才能访问该接口 permission_classes=[MyPermision,] def get(self,request): #request.user 就是当前登录用户 print(request.user.name) return Response('返回了所有图书') class Publish(APIView): # authentication_classes = [MyAuth, ] permission_classes=[] def get(self,request): print(request.user.name) return Response('返回了所有出版社信息') class Login(APIView): authentication_classes = [] def post(self,request): response={'code':100,'msg':'登录成功'} name=request.data.get('name') pwd=request.data.get('pwd') try: #get 有且只有一条才不报错,其他都抛异常 user=models.User.objects.filter(name=name,pwd=pwd).get() #登录成功,需要去token表中存数据 #生成一个唯一的idhg token=uuid.uuid4() models.Token.objects.update_or_create(user=user,defaults={'token':token}) response['token']=token except ObjectDoesNotExist as e: response['code']=101 response['msg']='用户名或密码错误' except Exception as e: response['code'] = 102 # response['msg'] = '未知错误' response['msg'] = str(e) return Response(response)
附:不存数据库的token验证:
def get_token(id,salt='123'): import hashlib md=hashlib.md5() md.update(bytes(str(id),encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) return md.hexdigest()+'|'+str(id) def check_token(token,salt='123'): ll=token.split('|') import hashlib md=hashlib.md5() md.update(bytes(ll[-1],encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) if ll[0]==md.hexdigest(): return True else: return False class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') success=check_token(token) if success: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass class Login(APIView): def post(self,reuquest): back_msg={'status':1001,'msg':None} try: name=reuquest.data.get('name') pwd=reuquest.data.get('pwd') user=models.User.objects.filter(username=name,password=pwd).first() if user: token=get_token(user.pk) # models.UserToken.objects.update_or_create(user=user,defaults={'token':token}) back_msg['status']='1000' back_msg['msg']='登录成功' back_msg['token']=token else: back_msg['msg'] = '用户名或密码错误' except Exception as e: back_msg['msg']=str(e) return Response(back_msg) from rest_framework.authentication import BaseAuthentication class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if token_obj: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass class Course(APIView): authentication_classes = [TokenAuth, ] def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
总结:局部使用,只需要在视图类里加入:
authentication_classes = [TokenAuth, ]
三 全局使用:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",] }
四 源码分析:
#Request对象的user方法 @property def user(self): the authentication classes provided to the request. if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user def _authenticate(self): for authenticator in self.authenticators: try: user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise #认证成功,可以返回一个元组,但必须是最后一个验证类才能返回 if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple return self._not_authenticated()
self.authenticators
def get_authenticators(self): return [auth() for auth in self.authentication_classes]
认证类使用顺序:先用视图类中的验证类,再用settings里配置的验证类,最后用默认的验证类