Django Rest Framework(三) 之权限认证及源码流程

权限认证的方法流程与用户认证的方法流程基本一样,也包括全局与局部认证,内部认证等

 

内置的权限认证类

from rest_framework.permissions import BasePermission

#默认基础认证类
class BasePermission(object):
   
    def has_permission(self, request, view):
        
        return True

    def has_object_permission(self, request, view, obj):
       
        return True

#允许所有人
class AllowAny(BasePermission):

    def has_permission(self, request, view):
        return True

 

源码流程

self.dispatch下的initial方法

    def initial(self, request, *args, **kwargs):
       
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        self.perform_authentication(request)          #进行用户认证的方法
        self.check_permissions(request)             #进行权限认证的方法,源码看下面
        self.check_throttles(request)

 

self.check_permissions函数源码

    def check_permissions(self, request):
        for permission in self.get_permissions():      #首先去自定义的views里查找有没有这个get_permission方法,没有去父类(APIView)找
        if not permission.has_permission(request, self):        #这里红色字体为自定义时必须的函数名 self.permission_denied( request, message=getattr(permission, 'message', None)    #这里message为认证失败时的提示信息,可在views里自定义 )

 

父类(APIView)下的 get_permissions方法,

def get_permissions(self):
        
        return [permission() for permission in self.permission_classes]    #首先去自定义的views下去找有没有 permission_classes配置,没有继续从父类(APIView)下找

 

父类里的设置(在rest_framework下的settings.py里设置,获取相关的认证的实例化对象)

permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES    #这里即可定义全局的权限类,同样可以再settings里定义设置

 

定义全局与局部权限类

项目目录 settings.py

#utils为自定义创建的目录,用来存放用户认证、权限认证的文件,auth为自己定义创建的认证的文件,Authencation和Permission为自定义的认证函数

import
utils REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES":['utils.auth.Authication'],    #自定义用户认证的类 "DEFAULT_PERMISSION_CLASSES":['utils.auth.Permission']        #自定义权限认证类 }

此时,就定义了全局的权限认证类,如果要定义局部的权限认证类,同定义局部用户认证的类的方法一样,在相应的函数下加上

permission_classes = [MyPermission,]    #MyPermission为自定义权限认证的类名,如果不认证,写空列表即可

 如果在views.py里写了,就不会去全局配置文件里加载这个配置

 

自定义权限认证示例

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.request import Request
# Create your views here.
from api_test import models
import time,hashlib
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication    #内置的用户认证的类
from rest_framework.permissions import
BasePermission        #内置的权限认证的类

#范例数据 order_dict = { 1:{ "name":"apple", 'price':'15', 'addr':'bj', 'date':'2018-06-01' }, 2:{ "name":"tomato", 'price':'5', 'addr':'bj', 'date':'2018-06-01' } } 

#自定义用户认证的类
class Authication(BaseAuthentication):
  '''获取token进行用户认证 '''
#self.dispatch()
def authenticate(self,request): current_token = request._request.GET.get('token') obj_token = models.UserToken.objects.filter(token=current_token).first() if not obj_token: raise exceptions.AuthenticationFailed("用户认证失败") #在rest_framework内部会将这两个字段赋值给request,以后供后续操作使用,实现原理看用户认证流程 return (obj_token.user,obj_token) def authenticate_header(self, *args): pass

#自定义权限认证类 class MyPermission(BasePermission):
  message = "权限认证失败"    #自定义认证失败提示信息, def has_permission(self,request,view): if request.user.user_type != 3: return False return True
def md5(user):
  '''生成加密的token'''
ctime
= str(time.time()) m = hashlib.md5(bytes(user,encoding="utf-8")) m.update(bytes(ctime,encoding="utf-8")) return m.hexdigest()
class AuthView(APIView): ''' 用户登录认证,生成token ''' def post(self,request,*args,**kwargs): ret = {'code':10000,'msg':None} try: user = request._request.POST.get("username") #因为这里继承的Apiview,经过处理后的request,需要通过request._request才能获取原生request内的值,具体看Request函数 pwd = request._request.POST.get("password") obj = models.UserInfo.objects.filter(username=user,password=pwd).first() if not obj: ret['code'] = 10001 ret['msg'] = "用户名密码错误" #如果用户不存在,则创建token,如果用户存在,则更新token token = md5(user) models.UserToken.objects.update_or_create(user=obj,defaults={'token':token}) ret['token'] = token except Exception as e: ret['code'] = 10002 ret['msg'] = "请求异常" return JsonResponse(ret) class OrderView(APIView): ''' 订单业务接口(只有超级用户可访问) ''' # self.dispatch authentication_classes = [Authication,] permission_classes = [MyPermission,]      #加载认证的类,原理看认证流程,与用户认证流程一样
def get(self,request,*args,**kwargs): print (request.user,request.auth)     #打印用户信息 ret = {'code': 10000, 'msg': None} try: ret['data'] = order_dict except Exception as e: pass return JsonResponse(ret) def post(self,request,*args,**kwargs): pass def put(self,request,*args,**kwargs): pass def delete(self,request,*args,**kwargs): pass

 

posted @ 2018-06-25 14:24  FRESHMANS  阅读(297)  评论(0)    收藏  举报