Python+Django+rest_framework实现权限控制

权限控制,即对已登录的用户进行访问权限的控制。

1.创建表:用户表UserInfo、token表 UserToken,权限表一 CommonVideo, 权限表二 VIPVideo

from django.db import models
from datetime import datetime
# Create your models here.

class UserInfo(models.Model):
    """
    用户表
    """
    user_type_choices=(
        (1, "普通用户"),
        (2, "VIP"),
        (3, "SVIP")
    )
    user_type = models.IntegerField(choices=user_type_choices)
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
    class Meta:
        verbose_name = '用户表'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.username

class UserToken(models.Model):
    """
    Token表
    """
    user = models.ForeignKey(UserInfo, on_delete=models.CASCADE)
    token = models.CharField(max_length=64)
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
    class Meta:
        verbose_name = 'token表'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.user.username

class CommonVideo(models.Model):
    """
    普通视频
    """
    title = models.CharField(max_length=32)
    url = models.CharField(max_length=200, verbose_name='资源地址')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')
    class Meta:
        verbose_name = '普通视频表'
        verbose_name_plural = verbose_name
    def __str__(self):
        return self.title


class VIPVideo(models.Model):
    """
    会员视频
    """
    title = models.CharField(max_length=32)
    url = models.CharField(max_length=200, verbose_name='资源地址')
    add_time = models.DateTimeField(default=datetime.now, verbose_name='添加时间')

    class Meta:
        verbose_name = '会员视频表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title

2.执行数据更新命令

python manage.py makemigration
python manage.py migrate

3.在UserInfo表中插入两条用户数据,user1 user_type=1, user2 user_type=2

4.分别在普通视频表和VIP视频表分别插入一条数据

5.安装Django REST Framework依赖

pip install djangorestframework markdown django-filter

6.settings文件添加配置

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework', #新添加的配置
]

#新添加的配置
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':(
        'app01.utils.auth.Authentication',
    )
}

7.在应用下,如设置的应用时app01,即在app01目录下新建一个utils目录,在该目录下新建一个auth.py文件,代码如下

from ..models import *
from rest_framework import exceptions
class Authentication(object):
    def authenticate(self, request):
        # 验证是否已经登录,函数名必须为:authenticate
        token = request._request.GET.get('token')
        token_obj = UserToken.objects.filter(token=token).first()
        print(token_obj)
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        # rest_framework内部会将以下元素赋值到request,以供后续使用
        return (token_obj.user, token_obj)

    def authenticate_header(self, request):
        # 这个函数可以没有内容,但是必须要有这个函数
        pass

class VIP(object):
    """
    验证VIP权限
    """

    def has_permission(self, request, view):
        if request.user.user_type < 2:
            return False
        return True

8.在app01目录下新建序列化模块文件,serializers.py,代码如下:

from rest_framework import serializers
from .models import CommonVideo, VIPVideo, SVIPVideo
class CommonVideoSerializer(serializers.ModelSerializer):
    class Meta:
        model = CommonVideo
        fields = "__all__"

class VIPVideoSerializer(serializers.ModelSerializer):
    class Meta:
        model = VIPVideo
        fields = "__all__"

class SVIPVideoSerializer(serializers.ModelSerializer):
    class Meta:
        model = SVIPVideo
        fields = "__all__"

9.编写view.py的代码

from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.views import APIView
from .models import *
from .serializers import *
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
from rest_framework import exceptions
from .utils.auth import Authentication
from .utils.auth import VIP
# Create your views here.

def md5(user):
    import hashlib
    import time
    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):
    """
    登录
    """
    authentication_classes = []
    def post(self, request):
        ret = {'code':1000, 'msg':'登录成功!'}
        try:
            user = request._request.POST.get('username')
            pwd = request._request.POST.get('password')
            obj = UserInfo.objects.filter(username=user, password=pwd).first()
            #print(user,pwd,obj)
            if not obj:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
                return JsonResponse(ret)
            #为登录用户创建token
            token = md5(user)
            #存在则更新,不存在的创建
            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)

class Authentication(object):
    def authenticate(self, request):
        #验证是否已经登录,函数名必须为:authenticate
        token = request._request.GET.get('token')
        token_obj = UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        #在rest_framework内部会将以下两个元素赋值到request,以供后续使用
        return (token_obj.user, token_obj)
    def authenticate_header(self, request):
        #这个函数可以没有内容,但是必须要有这个函数
        pass

class CommonVideoView(APIView):
    """
    登录后即可访问的内容资源
    """
    renderer_classes = [JSONRenderer]
    #渲染器
    authentication_classes = [Authentication,]
    def get(self, request):
        video_list = CommonVideo.objects.all()
        re = CommonVideoSerializer(video_list, many=True)
        return Response(re.data)

class VIPVideoView(APIView):
    """
    VIP可访问的资源
    """
    renderer_classes = [JSONRenderer]
    #渲染器
    permission_classes = [VIP,]
    def get(self, request):
        video_list = VIPVideo.objects.all()
        re = VIPVideoSerializer(video_list, many=True)
        print("***",video_list, re)
        return Response(re.data)

10.urls.py文件中添加路由

from django.contrib import admin
from django.urls import path
from app01.views import AuthView, CommonVideoView, VIPVideoView
urlpatterns = [
    path('admin/', admin.site.urls),
    path('auth/', AuthView.as_view(), name = 'auth'),
    path('common/', CommonVideoView.as_view(), name='common'),
    path('vip/', VIPVideoView.as_view(), name='vip'),
]

验证

1.使用postman,post请求登录user1

2.登录成功,使用登录成功返回的token访问common,返回commonVideo表数据信息,访问vip,提示无权限

3.使用postman,post请求登录user2

4.登录成功,使用登录成功返回的token访问common,返回commonVideo表数据信息,访问vip,返回VIPVideo表数据信息

猜你喜欢

转载自www.cnblogs.com/dayan007/p/12914008.html