$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()
choices
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)
dj2必须写on_delete,dj1默认models.CASCADE

二 认证组件

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 ('你还没有登陆')
认证组件重点authenticate(self,request)返回元组(request.user,request.auth)或者异常
#局部使用
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)
Login

三 权限组件(认证组件通过后可以拿到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
权限组件重点has_permission(self,request,view)判断权限字段为vip返回False,不足返回True.message='请先升级用户'
#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







posted @ 2018-12-12 20:32  带飞  阅读(235)  评论(0编辑  收藏  举报