在阅读本文以前请先参考django rest framework 之 认证中关于django rest framework
的相关内容及实例html
为了更好的管理各个功能组件,在django rest framework 之 认证中咱们说到能够将认证类单独的拿出来,放到其余目录下,而后导入到views.py
文件中,在权限环节咱们亦能够这么作,目录结构就变成这样sql
在api这个app下建立一个utils包专门用来存放相关的组件。数据库
咱们在models.py中定义了两个模型类,分别是django
from django.db import models class UserInfo(models.Model): USER_TYPE = ( (1,'普通用户'), (2,'VIP'), (3,'SVIP') ) user_type = models.IntegerField(choices=USER_TYPE, default=1) username = models.CharField(max_length=32) password = models.CharField(max_length=64) class UserToken(models.Model): user = models.OneToOneField(UserInfo,on_delete=models.CASCADE) token = models.CharField(max_length=64)
在UserInfo
中经过为用户添加一个user_type
字段来保证用户的身份,是普通用户,VIP仍是SVIP,这样就能够经过用户的身份验证不一样的权限。若是想要定义一个视图类,这个类中的逻辑只有超级用户才能访问。json
能够再utils中的permissions.py
中这么写api
# utils/permission.py class SVIPPremission(object): message = "必须是SVIP才能访问" # 这里的message表示若是不经过权限的时候,错误提示信息 def has_permission(self,request,view): if request.user.user_type != 3: return False return True class MyPremission(object): # 这个权限类表示当用户为SVIP时不可经过 def has_permission(self,request,view): if request.user.user_type == 3: return False return True
这里只是判断用户的USER_TYPE
的字段,判断用户是否有权限,也能够添加其余的逻辑进行判断。浏览器
在上一节的django rest framework 之 认证的认证中,将认证类放到了settings.py
文件中,这样会做用到视图中的每个视图类,若是视图类想要本身进行认证,只须要重写authentication_classes
便可,那么对于权限来讲咱们也能够这么作,app
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.authenticate.FirstAuthenticate', 'api.utils.authenticate.MyAuthenticate'], "UNAUTHENTICATED_USER": None, # 匿名,request.user = None "UNAUTHENTICATED_TOKEN": None,# 匿名,request.auth = None "DEFAULT_PERMISSION_CLASSES": ['api.utils.permission.MyPermission'], # 表示每个视图类(只要不重写permission_classes属性),都须要SVIP的用户才能访问。 }
在视图view.py
中定义一个用户详情类UserInfoView
做为测试,这里的视图和上一节的django rest framework 之 认证是相接的。源码分析
from django.shortcuts import render, HttpResponse from django.http import JsonResponse from django.views import View from rest_framework.views import APIView from rest_framework.request import Request from .utils import authenticate, permission from api import models import json def md5(user): import hashlib import time # 当前时间,至关于生成一个随机的字符串 ctime = str(time.time()) # token加密 m = hashlib.md5(bytes(user, encoding='utf-8')) m.update(bytes(ctime, encoding='utf-8')) return m.hexdigest() class AuthView(APIView): '''用于用户登陆验证''' authentication_classes = [] #里面为空,表明不须要认证 permission_classes = [] #不里面为空,表明不须要权限 def get(self, request, *args, **kwargs): ret = {'code': 1000, 'msg': 'success', 'name': '偷偷'} ret = json.dumps(ret, ensure_ascii=False) return HttpResponse(ret) def post(self,request,*args,**kwargs): ret = {'code':1000,'msg':None} try: user = request.POST.get('username') pwd = request.POST.get('password') print(user, pwd) obj = models.UserInfo.objects.filter(username=user,password=pwd).first() print(obj.username, obj.password) if not obj: ret['code'] = 1001 ret['msg'] = '用户名或密码错误' #为用户建立token token = md5(user) #存在就更新,不存在就建立 models.UserToken.objects.update_or_create(user=obj,defaults={'token':token}) ret['token'] = token except Exception as e: ret['code'] = 1002 ret['msg'] = '请求异常' return JsonResponse(ret) ORDER_DICT = { 1:{ 'name':'apple', 'price':15 }, 2:{ 'name':'狗子', 'price':100 } } class OrderView(APIView): # 用户想要获取订单,就要先经过身份认证、在全局settings.py 中已经配置 permission_classes = [] def get(self, request, *args, **kwargs): ret = { 'code': 1024, 'msg': '订单获取成功', } try: ret['data'] = ORDER_DICT except Exception as e: pass return JsonResponse(ret) class UserInfoView(APIView): permission_classes = [permission.SVIPPermission] def get(self, request, *args, **kwargs): print(request.user) return HttpResponse('SVIP用户信息')
这里的UserInfoView
重写了permission_classes
属性,则不会再使用settings.py
中关于认证类的配置。表示只有SVIP才能访问这个类的内部。post
在url.py中设置路由分发
from django.conf.urls import url from api.views import AuthView, OrderView, UserInfoView urlpatterns = [ url(r'^api/v1/auth/$', AuthView.as_view()), url(r'^api/v1/order/$', OrderView.as_view()), url(r'^api/v1/info/$', UserInfoView.as_view()), ]
Postman或者浏览器发送请求,因为咱们在setting.py
中配置了 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.authenticate.FirstAuthenticate', 'api.utils.authenticate.MyAuthenticate'],
会对请求进行认证,因此要带这用户的token
才能经过,进入到权限组件。
进入sqlite数据库,找到对应的注册用户
在数据库中,拿到刷新的用户的最近一次的token
拿到这个token发送请求
请求成功,则说明权限生效,也能够在将UserInfoView
改为以下
class UserInfoView(APIView): permission_classes = [permission.SVIPPermission] def get(self, request, *args, **kwargs): print(request.user) return HttpResponse('SVIP用户信息')
在发送请求,就会发现用户不会有权限的提示信息。以下
像django rest framework 之 认证同样进入,request
的请求流程,进入源码查看具体权限的操做
在这里能够看到和认证中有相似的操做,获取全部的权限类,而且执行每个权限类的has_permission()
方法,而这个方法具体封装了咱们的判断权限操做,可是has_permission()
方法的返回值须要时False
或者True
, self.permission_denied(request, message=getattr(permission, 'message', None))
说明能够在权限类中重写message
属性,来定义权限不经过时候的提示信息。
进入self.get_permissions()
来看一下
在APIView中有定义默认的权限类,所以也能够经过全局配置的方法配置权限类。
像认证那样,django rest framework
中也有权限类
能够根据本身的须要调用。
权限其实的流程跟以前的认证流程是同样的,认证类封装到request
中,而后再调用认证类的方法,不过这里的方法返回值再也不是像认证组件那样的直接返回一个认证的对象,而是返回一个True
或者False
值表示认证过的对象是否有某些权限再进行具体操做。
这里注意的是,在本身重写权限类的相关方法,添加本身的逻辑的时候,返回值须要是一个布尔值,Flase
或者True
,表示是否有权限。也能够经过全局配置和局部配置权限类。