zoukankan      html  css  js  c++  java
  • 从FBV到CBV三(权限)

    丛FBC到CBV三(权限)

    权限

    准备数据表                     

    用户组(group)
    id group_name
    1 usual
    2 vip
    3 svip
    4 admin
    用户(user)
    id username password group_id
    1 Joshua 123 1
    2 William 123 2
    3 Daniel 123 3
    4 Michael 123 4
     
    创建项目及app:
                    
     
        models.py
     
     
     
    19
     
     
     
     
     
    1
    # -*- coding:utf-8 -*-
    2
    from django.db import models
    3
    
    
    4
    class Group(models.Model):
    5
        id = models.AutoField(primary_key=True)
    6
        group_name = models.CharField(max_length=40)
    7
    
    
    8
        class Meta:
    9
            db_table = 'group'
    10
    
    
    11
    class User(models.Model):
    12
        id = models.AutoField(primary_key=True)
    13
        username = models.CharField(max_length=40,unique=True)
    14
        password = models.CharField(max_length=40)
    15
        group_id = models.ForeignKey(Group, default=1)
    16
    
    
    17
        class Meta:
    18
            db_table = 'user'
    19
    
    
     
     
    views.py
     
     
     
    16
     
     
     
     
     
    1
    from django.http.response import JsonResponse
    2
    from rest_framework.views import APIView
    3
    
    
    4
    from permissions.models import User, Group
    5
    
    
    6
    
    
    7
    class Users(APIView):
    8
        def get(self, request):
    9
            users = User.objects.all().values()
    10
            return JsonResponse(list(users), safe=False)
    11
    
    
    12
    
    
    13
    class Groups(APIView):
    14
        def get(self, request):
    15
            groups = Group.objects.all().values()
    16
            return JsonResponse(list(groups), safe=False)
     
     
     urls.py
     
     
     
    9
     
     
     
     
     
    1
    from django.conf.urls import url
    2
    from django.contrib import admin
    3
    from permissions.views import Users, Groups
    4
    
    
    5
    urlpatterns = [
    6
        url(r'^admin/', admin.site.urls),
    7
        url(r'^user/$', Users.as_view(), name='user'),
    8
        url(r'^group/$', Groups.as_view(), name='group'),
    9
    ]
     
     
    Postman提交请求:
        
                 

                 

     
    现在新建了一张MemberPrograms表,里面的内容是只给会员用户展示的
    实现这个功能:
    会员项目(member_programs)
    id program_name
    1 书法长卷
    2 书法碑帖
    3 墓志塔铭
    4 兰亭集序
     
    定义models
     
     
     
    6
     
     
     
     
     
    1
    class MemberProgram(models.Model):
    2
        id = models.AutoField(primary_key=True)
    3
        program_name = models.CharField(max_length=100)
    4
    
    
    5
        class Meta:
    6
            db_table = 'member_program'
     
     
    定义url以及视图函数:
     
     
     
    9
     
     
     
     
     
    1
    from django.conf.urls import url
    2
    
    
    3
    from permissions.views import Users, Groups, MemberPrograms
    4
    
    
    5
    urlpatterns = [
    6
        url(r'^user/$', Users.as_view(), name='user'),
    7
        url(r'^group/$', Groups.as_view(), name='group'),
    8
        url(r'^program/$', MemberPrograms.as_view(), name='program'),
    9
    ]
     
     
     
     
     
     
    4
     
     
     
     
     
    1
    class MemberPrograms(APIView):
    2
        def get(self, request):
    3
            programs = MemberProgram.objects.all().values()
    4
            return JsonResponse(list(programs), safe=False)
     
     
    测试:
                
    现在接口已经实现了,但是我们要对这个接口增加权限控制,只允许vip,svip,admin用户访问,代码实现:
        方法一:
        上一章我们实现了自定义认证的中间件,现在可以利用起来,修改如下:
     
     
     
     
    25
     
     
     
     
     
    1
    class MyAuthentication(BaseAuthentication):
    2
        def authenticate(self, request):
    3
            name = request._request.GET.get('username')
    4
            print(name)
    5
            return (name, None)
    6
    
    
    7
    
    
    8
    class MemberPrograms(APIView):
    9
        authentication_classes = [MyAuthentication, ]
    10
    
    
    11
        def get(self, request):
    12
            if not request.user:            # 没有用户身份,不允许访问
    13
                ret = {'code': 1002, 'error': '权限被拒'}
    14
                return JsonResponse(ret)
    15
            username = request.user
    16
            try:
    17
                group_name = User.objects.get(username=username).group.group_name  
    18
            except User.DoesNotExist:            # 用户身份不存在,返回错误信息
    19
                ret = {'code': 1003, 'error': '用户不存在'}
    20
                return JsonResponse(ret)
    21
            if group_name == 'usual':           # 是普通用户,没有权限
    22
                ret = {'code': 1002, 'error': '权限被拒'}
    23
                return JsonResponse(ret)             
    24
            programs = MemberProgram.objects.all().values()    # 用户权限满足条件 返回接口信息
    25
            return JsonResponse(list(programs), safe=False)
     
     
    测试:
                  
                   

                 

                  

    上面实现了接口对用户权限的控制,实际项目代码不会这么简单,需要通过token进行判断,这里只是简单实现
    方法二:
        利用restframework的permission组件实现:
     
     
     
    x
     
     
     
     
     
    1
    from rest_framework.authentication import BaseAuthentication
    2
    from rest_framework.permissions import BasePermission
    3
    from rest_framework.exceptions import PermissionDenied
    4
    
    
    5
    lass MyAuthentication(BaseAuthentication):
    6
        def authenticate(self, request):
    7
            name = request._request.GET.get('username')
    8
            print(name)
    9
            return (name, None)
    10
    
    
    11
    
    
    12
    class MyPermission(BasePermission):
    13
        def has_permission(self, request, view):
    14
            if not request.user:
    15
                raise PermissionDenied('权限被拒')
    16
            username = request.user
    17
            try:
    18
                group_name = User.objects.get(username=username).group.group_name
    19
            except User.DoesNotExist:
    20
                raise PermissionDenied('用户不存在')
    21
            if group_name == 'usual':
    22
                raise PermissionDenied('权限被拒')
    23
            return True
    24
    
    
    25
    
    
    26
    class MemberPrograms(APIView):
    27
        authentication_classes = [MyAuthentication, ]
    28
        permission_classes = [MyPermission, ]
    29
    
    
    30
        def get(self, request):
    31
            programs = MemberProgram.objects.all().values()
    32
            return JsonResponse(list(programs), safe=False)
     
     
         上面的例子中我们都是将认证类和权限类注册在了对应的view视图中,
          其实要是项目中多数视图需要进行以上验证,那就可将自定义的认证类和权限类放在一个单独的文件中,然后注册到seeting.py中 :
      
              

             

    在seeting.py中添加下面内容:
                
    源码分析:
                  
        1.请求的封装,将原先的request封装到restframework的APIview中,丰富了request内容,包含了authenticators等
        2. initial() 初始化
     
     
     
    x
     
     
     
     
    1
        def initial(self, request, *args, **kwargs):
    2
            """
    3
            Runs anything that needs to occur prior to calling the method handler.
    4
            """
    5
            self.format_kwarg = self.get_format_suffix(**kwargs)
    6
    
    
    7
            # Perform content negotiation and store the accepted info on the request
    8
            neg = self.perform_content_negotiation(request)
    9
            request.accepted_renderer, request.accepted_media_type = neg
    10
    
    
    11
            # Determine the API version, if versioning is in use.
    12
            version, scheme = self.determine_version(request, *args, **kwargs)
    13
            request.version, request.versioning_scheme = version, scheme
    14
    
    
    15
            # Ensure that the incoming request is permitted
    16
            
    17
            # 身份验证
    18
            self.perform_authentication(request)
    19
            # 权限验证
    20
            self.check_permissions(request)
    21
            self.check_throttles(request)
     
     
               调用了self.check_permissions(request)
     
     
     
    x
     
     
     
     
     
    1
        def check_permissions(self, request):
    2
            """
    3
            Check if the request should be permitted.
    4
            Raises an appropriate exception if the request is not permitted.
    5
            """
    6
            for permission in self.get_permissions():    # 1
    7
                if not permission.has_permission(request, self):  # 2
    8
                    self.permission_denied(    # 3
    9
                        request, message=getattr(permission, 'message', None)
    10
                    )
     
     
        第一步: self.get_permissions:
     
     
     
    x
     
     
     
     
    1
        def get_permissions(self):
    2
            """
    3
            Instantiates and returns the list of permissions that this view requires.
    4
            """
    5
            return [permission() for permission in self.permission_classes]
    6
        
    7
        
    8
    self.permission_classes 就是我们定义的permissions,默认是从seeting.py配置文件中找,如果我们的view中制定了这一项,就使用view中的permission,而不用配置文件中的    
    9
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES   
     
     
              第二步:permission.has_permission
              此时的permission就是定义的permission类,既然调用了has_permission方法,那我们的permission类就必须实现这个方法,这个方法中用来实现我们的权限校验逻辑
              源码判断这个函数,if not,说明如果has_permission函数的返回值不是True,就到第三步,否则集序循环下一个permission
              
              第三步:self.permission_denied
              可以看到这个方法需要两个参数,一个是request,一个是message=getattr(permission, 'message', None),getattr()从permission中找message,没找到就设为Node
     
     
     
    x
     
     
     
     
     
    1
        def permission_denied(self, request, message=None):
    2
            """
    3
            If request is not permitted, determine what kind of exception to raise.
    4
            """
    5
            if request.authenticators and not request.successful_authenticator:
    6
                raise exceptions.NotAuthenticated()
    7
            raise exceptions.PermissionDenied(detail=message)
     
     
              permission_denied最终抛出了一个异常exceptions.PermissionDenied,这个异常接受了message,而它实际就是我们异常的提示语,所以,可以修改上面自定义的MyPermission类,不需要我们手动抛出异常,只要return False即可:

     
     
     
    x
     
     
     
     
     
    1
    class MyPermission(BasePermission):
    2
        
    3
        message = '需要会员用户才能访问'
    4
        
    5
        def has_permission(self, request, view):
    6
            if not request.user:
    7
                return False
    8
            username = request.user
    9
            try:
    10
                group_name = User.objects.get(username=username).group.group_name
    11
            except User.DoesNotExist:
    12
                return False
    13
            if group_name == 'usual':
    14
                return False
    15
            return True
     
     
            测试:
                
                
     
  • 相关阅读:
    邻居子系统 之 更新neigh_update
    邻居子系统 之 邻居项查找neigh_lookup、___neigh_lookup_noref
    遍历集合的方法总结
    Java集合中List,Set以及Map等集合体系
    八大数据结构分类
    servlet和jsp的区别
    Web前端和Web后端的区分
    (转)为什么JavaWeb放弃jsp,去做前后端分离
    面向对象的三大基本特征和五大基本原则
    (转)2019年给Java编程初学者的建议(附学习大纲)
  • 原文地址:https://www.cnblogs.com/wangbaojun/p/10994310.html
Copyright © 2011-2022 走看看