restframework(6):权限组件

权限简介

权限说明

权限是针对某种对象的全局性的设置,而不是针对某种对象的某个特定实例的。例如,我们可以说“玛丽可以改写故事”,但是不能说“玛丽可以改写故事,但只限于她自己的故事”,也不能说“玛丽只能改写符合特定条件(如出版日期、编号)的故事”。后面的两种情况是 Django 的开发者正在讨论的东西,现在还不支持。

权限要求

目前,我们的API对谁可以编辑或删除代码段没有任何限制。我们希望有一些更高级的行为,以确保:

  • 代码段始终与创建者相关联。
  • 只有经过身份验证的用户才能创建摘要。
  • 只有代码段的创建者可以更新或删除它。
  • 未经身份验证的请求应具有完全只读访问权限。

restframework中的权限

权限即是通过继承BasePermission重构权限的类,权限的逻辑在类的has_permission方法中实现,返回True则有权限,返回False则没有权限。权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行对象访问权限的判断

restframework提供权限

  1. AllowAny 允许所有用户
  2. IsAuthenticated 仅通过认证的用户
  3. IsAdminUser 仅管理员用户
  4. IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取

权限简单实例

这里models还是上一篇博文中的那几张表,没有任何变动,我们需要注意的就是User类。

自定义权限类

这里的模型类我们不再解释了,在上一篇博文认证篇有详细的解释,这里的和上一篇的基本完全一致。
models.py

class User(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    type_choices=((1,"普通用户"),(2,"VIP"),(3,"SVIP"))
    user_type=models.IntegerField(choices=type_choices,default=1)

views.py

class SVIPPermission(object):
    message="只有超级用户才能访问"
    def has_permission(self,request,view):
        username=request.user
        user_type=User.objects.filter(name=username).first().user_type

        if user_type==3:
            return True # 通过权限认证
        else:
            return False

class MyPermission()

上面的自定义权限逻辑是判断我们的数据库中用户的等级机制问题,我们类比于以前的QQ,用户分为三级,普通,会员,超级会员。这里只是由于超级会员才让它通过权限,而在这之前,我们还可以介绍一下django中怎么直接用命令行创建用户。

用命令行创建用户

>>>python manage.py createuser

创建普通用户,部分特权。

>>>python manage.py createsuperuser

创建超级用户,在django中具有远超其它用户的最大的特权。

演示效果如下:
在这里插入图片描述

全局使用

我们可以在settings配置文件中增加配置:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

而如果我们不写这个配置,那么系统会默认执行:

'DEFAULT_PERMISSION_CLASSES': (
   'rest_framework.permissions.AllowAny',
)

局部使用

from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)
    ...

自定义权限的使用

我们可以从前面的模块中获取到新的权限,我们可以依然延续前面的验证类中的模式,那么我们的LoginViews函数基本无变化:

views.py:

class LoginView(APIView):
    # authentication_classes = [TokenAuth,]
    def post(self,request):
        name=request.data.get("name")
        pwd=request.data.get("pwd")
        user=User.objects.filter(name=name,pwd=pwd).first()
        res = {"state_code": 1000, "msg": None}
        if user:

            random_str=get_random_str(user.name)
            token=Token.objects.update_or_create(user=user,defaults={"token":random_str})
            res["token"]=random_str
        else:
            res["state_code"]=1001 #错误状态码
            res["msg"] = "用户名或者密码错误"

        import json
        return Response(json.dumps(res,ensure_ascii=False))

我们可以从中获取到信息的取值,然后通过获取到的信息去判断案例信息,进一步得到我们的结果,利用postman测试如下:

在这里插入图片描述

如果该用户的类型不是3,则会显示:
在这里插入图片描述

权限源码解析

这里同样源码的步骤是三部分,和上一篇的认证是类似的,因为他们都在dispatch这个函数里面。

View -> dispatch函数

def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        #对原始request进行加工,丰富了一些功能
        #Request(
        #     request,
        #     parsers=self.get_parsers(),
        #     authenticators=self.get_authenticators(),
        #     negotiator=self.get_content_negotiator(),
        #     parser_context=parser_context
        # )
        #request(原始request,[BasicAuthentications对象,])
        #获取原生request,request._request
        #获取认证类的对象,request.authticators
        #1.封装request
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            #2.认证
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

初始化initial

    def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        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)  # 频率功能

然后这里也没有什么能解释的,在上一篇都有详细的说法,我就不再复述了,那么我们来看权限函数里面到底有什么:

上述调用的两个函数

check_permissions函数

    def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )
                

函数的意思很明显,我们可以从它里面判断出获取到的信息值,如果是self.permission_denied的步骤那么我们可以省略,permission可以根据反射原理获取到值,那么我们继续来看剩下的三个函数,其中permission_denied函数本身是作为处理请求异常函数,我们这里不做多介绍,那么只介绍另外两个函数:


get_permissions()

    def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        return [permission() for permission in self.permission_classes]

这个相当于向我们用户获取权限,如果我们用户没有赋值的话,那么就进入下一个函数里面,继续获取权限。加了一层循环遍历后得到结果。

permission_classes默认设置

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

所以权限组件整体的源码比认证简单一些,因为认证组件还需要去找当前的user的静态方法在哪里,但权限基本就一个函数里面就调用完全了。

总结

认证组件和权限组件花了两天时间,整体上理解没什么难度,因为不管懂不懂源码,其实配置起来就一句话,而如果仔细去分析源码,一步步去抽丝剥茧,那么这两个的层数并不是很多,不像以前看django源码的时候,一次七八层,然后最后导致是有些懵,截止到目前,restframework的解析也写了六篇了,原计划是写十篇左右,下一篇看情况写下频率组件或者是路由吧,但其实频率的源码步骤是和认证、权限一样的,如果有时间,我会将其再补齐一下的。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值