摘要:描述針對同一個,對不同的接口設(shè)置不同的權(quán)限看了源碼通過源碼可以發(fā)現(xiàn),每次請求進來,都要做認證,權(quán)限驗證和限流驗證。
描述
針對同一個 view,對不同的接口設(shè)置不同的權(quán)限
看了 DRF views 源碼:
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)
通過源碼可以發(fā)現(xiàn),每次請求進來,都要做認證,權(quán)限驗證和限流驗證。如果所有接口都需要權(quán)限,這直接在視圖類中直接設(shè)置 permission_classes 即可;如果針對業(yè)務(wù)中部分接口需要權(quán)限,其他不需要權(quán)限的場景,這樣一刀切的方式是行不通的,因為進來的請求會被權(quán)限打回去,針對部分接口需要權(quán)限的場景,可能需要變通一下。
1 場景如下:例如個人博客例如有個分類模型
class Category(models.Model): name = models.CharField("名稱", max_length=30) created = models.DateTimeField("生成時間", auto_now_add=True) def __str__(self): return self.name
如果使用 DRF 的 viewset
class CategoryViewSet(viewsets.ModelViewSet): queryset = Category.objects.all() serializer_class = CategorySerializer
DRF 會自動生成六個方法,具體就不說了,對于個人博客來說,獲取列表以及詳情是不需要設(shè)置權(quán)限的,但是對于更新,創(chuàng)建,刪除時需要做權(quán)限驗證的,那么問題來了,我該怎么做好權(quán)限驗證,這里我假使獲取詳情需要管理員權(quán)限,其他方法都不需要權(quán)限驗證
2 變通方式 方法 1:自定義裝飾器寫包裝權(quán)限的裝飾器
from functools import update_wrapper def wrap_permission(*permissions, validate_permission=True): """custom permissions for special route""" def decorator(func): def wrapper(self, request, *args, **kwargs): self.permission_classes = permissions if validate_permission: self.check_permissions(request) return func(self, request, *args, **kwargs) return update_wrapper(wrapper, func) return decorator
自定義權(quán)限類
from rest_framework.permissions import IsAdminUser class IsVbAdminUser(IsAdminUser): """ Allows access only to admin users. """ def has_object_permission(self, request, view, obj): """ Return `True` if permission is granted, `False` otherwise. """ return self.has_permission(request, view)
然后在 viewset 中,例如獲取詳情接口,這樣用,
@wrap_permission(IsVbAdminUser) def retrieve(self, request, *args, **kwargs):
如果直接請求,就會下面錯誤
"error_message": "Authentication credentials were not provided."
后面在 DRF 的裝飾器中找到 permission_classes
def permission_classes(permission_classes): def decorator(func): func.permission_classes = permission_classes return func return decorator
這個默認的業(yè)務(wù)還需要定制,根據(jù)自己業(yè)務(wù)需要了
方法2:使用 detail_route 或者 list_route@detail_route( url_path="test", permission_classes=(IsVbAdminUser, ), ) def test(self, request, *args, **kwargs):
這樣耍的原因,在看了 DRF route 源代碼,發(fā)現(xiàn)
method_kwargs = getattr(viewset, methodname).kwargs initkwargs = route.initkwargs.copy() initkwargs.update(method_kwargs)
是不是很好玩
對于自定義路由,使用這種方法,還是蠻方便的。
方法 3:重新定義 initial 方法重寫 initial 方法,根據(jù)方法定義不同的權(quán)限類
添加 permission_classes_map 類屬性
permission_classes_map 定義接口和權(quán)限的映射,用法如下:
permission_classes_map = { 方法名: 權(quán)限類列表 }
此為特定接口的權(quán)限檢測,例如如果視圖中包含 create 方法,同時在又在視圖中設(shè)置了全局性的 permission_classes,
但是想為 create 定義不同于全局的權(quán)限,所以這里可以這樣設(shè)置,示例如下:
permission_classes_map = { "create": [CustomPermission] }
permission_classes_map = {} def initial(self, request, *args, **kwargs): """重新定義此方法,添加靈活配置權(quán)限映射""" 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 if hasattr(handler, "__name__"): handler_name = handler.__name__ elif hasattr(handler, "__func__"): handler_name = handler.__func__.__name__ else: handler_name = None if handler_name and handler_name in self.permission_classes_map: if isinstance(self.permission_classes_map.get(handler_name), (tuple, list)): self.permission_classes = self.permission_classes_map.get(handler_name) return super(CommonWithSignViewSet, self).initial(request, *args, **kwargs)方法 4:使用不同的視圖
把需要權(quán)限驗證的和不需要權(quán)限驗證的視圖分開,寫兩個視圖,但是這樣做會冗余部分代碼
3 小結(jié)我在以往的經(jīng)歷中,如果是針對默認的路由需要加權(quán)限驗證,我會使用方法 1,對于自定義路由,我會使用方法 2,當(dāng)然也可以反過來思考,設(shè)置全局的權(quán)限驗證,如果那個方法不需要權(quán)限驗證,使用裝飾器把權(quán)限設(shè)置為空即可,隨便怎么折騰
前兩種方法盡量不要再視圖屬性中設(shè)置 permission_classes,這樣的處理有點奇葩,個人可以針對 DRF 處理流程,進行包裝,看業(yè)務(wù)需要。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/45444.html
摘要:描述針對同一個,對不同的接口設(shè)置不同的權(quán)限看了源碼通過源碼可以發(fā)現(xiàn),每次請求進來,都要做認證,權(quán)限驗證和限流驗證。 描述 針對同一個 view,對不同的接口設(shè)置不同的權(quán)限 看了 DRF views 源碼: def initial(self, request, *args, **kwargs): Runs anything that needs to occur pr...
摘要:描述針對同一個,對不同的接口設(shè)置不同的權(quán)限看了源碼通過源碼可以發(fā)現(xiàn),每次請求進來,都要做認證,權(quán)限驗證和限流驗證。 描述 針對同一個 view,對不同的接口設(shè)置不同的權(quán)限 看了 DRF views 源碼: def initial(self, request, *args, **kwargs): Runs anything that needs to occur pr...
摘要:自帶了一個健壯的緩存系統(tǒng)來保存動態(tài)頁面,避免每次請求都重新計算。緩存中的和方法是很常見的。盡量放在第一個繼承的類設(shè)置過期時間根據(jù)自己需求加緩存。目前這個緩存使用的是內(nèi)存。 概述:對于中等流量的網(wǎng)站來說,盡可能的減少開銷是非常必要的。緩存數(shù)據(jù)就是為了保存那些需要很多計算資源的結(jié)果,這樣的話就不必在下次重復(fù)消耗計算資源。獲取數(shù)據(jù)的數(shù)據(jù)的時候就是去緩存中拿,拿到了直接返回,沒拿到就去數(shù)據(jù)庫中...
摘要:微信支付統(tǒng)一下單接口,有一個叫的參數(shù),作用我就照搬官方文檔異步接收微信支付結(jié)果通知的回調(diào)地址,通知必須為外網(wǎng)可訪問的,不能攜帶參數(shù)。 最近在做一個小程序,小程序有涉及到微信支付,說來慚愧,還是第一次自己動手去做微信支付這一塊的實現(xiàn),所以過程中遇到了很多人都會踩的坑(例如mmp的微信支付各種key各種id要在哪里找,很難找),這次使用django來開發(fā),接口部分用django-rest-...
閱讀 822·2021-11-22 15:25
閱讀 1426·2021-09-08 09:45
閱讀 1718·2021-09-02 09:46
閱讀 1313·2019-08-30 15:56
閱讀 1542·2019-08-29 15:14
閱讀 1168·2019-08-29 13:06
閱讀 2021·2019-08-29 12:34
閱讀 1410·2019-08-26 12:14