一 認證簡介
只有認證通過的用戶才能訪問指定的url地址,比如:查詢課程信息,需要登錄之后才能查看,沒有登錄,就不能查看,這時候需要用到認證組件
二 局部使用
(1)models層:

class User(models.Model): username=models.CharField(max_length=32) password=models.CharField(max_length=32) user_type=models.IntegerField(choices=((1,'超級用戶'),(2,'普通用戶'),(3,'二筆用戶'))) class UserToken(models.Model): user=models.OneToOneField(to='User') token=models.CharField(max_length=64)
(2)新建認證類(驗證通過return兩個參數)

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
(3)view層

def get_random(name): import hashlib import time md=hashlib.md5() md.update(bytes(str(time.time()),encoding='utf-8')) md.update(bytes(name,encoding='utf-8')) return md.hexdigest() 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_random(name) 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) class Course(APIView): authentication_classes = [TokenAuth, ] def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
附:不存數據庫的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里配置的驗證類,最后用默認的驗證類