$Django Rest Framework-认证组件,权限组件 知识点回顾choices,on_delete
一 小知识点回顾
#orm class UserInfo (models.Model): id = models.AutoField (primary_key=True) name = models.CharField (max_length=32) pwd = models.CharField (max_length=32) choices = ((0, '普通用户'), (1, 'vip用户'), (2, '年费vip')) user_type = models.IntegerField (choices=choices, default=0) #view 获取汉字 request.user.get_user_type_display()
class Book (models.Model): # 表示外键关联到出版社表,当出版社表删除了该条数据,图书表中不删除,仅仅是把外键置空 # 同时存在null=True,on_delete=models.SET_NULL publish = models.ForeignKey (to='Publish', to_field='id', null=True, on_delete=models.SET_NULL)
二 认证组件
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import APIException from app01 import models from app01.get_token import get_token class Auth(BaseAuthentication): def authenticate(self,request): token=request.query_params.get('token') #存数据库的token # ret=models.UserToken.objects.filter(token=token).first() # 不用存的token if token: user_id=token.split('|')[1] token_=token.split('|')[0] ret=get_token(user_id) if ret==token_: # return ret.user,ret user = models.UserInfo.objects.filter (id=user_id).first () return user,user else: raise APIException('你还没有登陆') else: raise APIException ('你还没有登陆')
#局部使用 class Login(APIView): authentication_classes=[Auth,] def post(self,request): pass #全局使用 settings里面配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.Myauthentication.Auth',], } class Login(APIView): #局部禁用认证组件 authentication_classes=[] def post(self,request): pass
import hashlib import time def get_token(xxx): # 存数据库的token # md5=hashlib.md5() # md5.update(xxx.encode('utf-8')) # md5.update(str(time.time()).encode('utf-8')) #不存数据库的token md5=hashlib.md5() md5.update('天王盖地虎xx蘑菇炖小鸡'.encode('utf-8')) md5.update(str(xxx).encode('utf-8')) md5.update('自古英雄爱美人'.encode('utf-8')) return md5.hexdigest() class Login(APIView): #局部禁用认证组件,setting定义全局 authentication_classes=[] #局部使用认证组件 #authentication_classes=[Auth,] def post(self,request): name=request.data.get('name') pwd=request.data.get('pwd') response={'status':100,'msg':'登陆成功'} try: ret=models.UserInfo.objects.get(name=name,pwd=pwd) # 存数据库的token # token = get_token (ret.name) # models.UserToken.objects.update_or_create(user=ret,defaults={'token':token}) # 不用存的token token = get_token (ret.id) response['token']='{}|{}'.format(token,ret.id) except ObjectDoesNotExist: response['status']=101 response['msg']='用户名或密码不存在' except Exception: response['status'] = 102 response['msg'] = '未知错误' return JsonResponse(response,safe=False)
三 权限组件(认证组件通过后可以拿到request.user)
from rest_framework.permissions import BasePermission
class Per(BasePermission): message='请先升级用户' def has_permission(self,request,view): user_type=request.user.user_type if user_type==1: return True return False
#1局部使用 class Books(APIView): permission_classes=[Per,] def get(self,request): response={'status':100,'msg':'请求成功'} books=models.Book.objects.all() ser=Myserializers.Books(books,many=True) response['data']=ser.data return JsonResponse(response,safe=False) #2全局使用 settings里配置 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.Myauthentication.Auth',], 'DEFAULT_PERMISSION_CLASSES': ['app01.Mypermission.Per', ] } #配置好了全局默认使用 class Books(APIView): def get(self,request): response={'status':100,'msg':'请求成功'} books=models.Book.objects.all() ser=Myserializers.Books(books,many=True) response['data']=ser.data return JsonResponse(response,safe=False) #局部禁用 class Books(APIView): permission_classes=[] def get(self,request): response={'status':100,'msg':'请求成功'} books=models.Book.objects.all() ser=Myserializers.Books(books,many=True) response['data']=ser.data return JsonResponse(response,safe=False)
源码剖析
#一 Apiview的dispach方法 把Apiview的认证列表 封装进了request对象里 #二 Apiview执行认证方法 #self.perform_authentication(request) def perform_authentication(self, request): request.user #调用了user方法 #三 request.user方法 @property def user(self): if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() return self._user #四 self._authenticate() 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()
#一 Apiview的self.check_permissions(request)方法 # self.get_permissions()为Apiview的权限对象列表 def check_permissions(self, request): for permission in self.get_permissions(): if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) )
认证组件源码实现方式
总结: as_view()闭包函数如返回view的内存地址 ,内部的view返回dispach的执行结果
1->apiview的as_view() 重用view的as_view() 返回了一个
csrf_exempt(view)
2->apiview自己的dispach方法内
(重新包装request,调用了认证【返回request.user】权限频率方法,判断reques.method 在没在 view类下的请求方式列表内 )
返回request.method.请求方式()/抛出异常执行结果执行
3->apiview定义了
authentication_classes地址列表 执行了自己的方法
authenticators=self.get_authenticators()拿到一个个对象列表
传入request类生对象
4—>requst.user
再request类中
for循环列表对象
调了列表对象类的
ret=authenticator.authenticate(self) #self为request对象
return self.user,self.auth