簡體   English   中英

安全刪除用戶的DRF和令牌認證?

[英]DRF and Token authentication with safe-deleted users?

我正在使用名為django-safedelete的Django包,它允許刪除用戶而不從數據庫中刪除它們。

基本上,它會向模型添加一個delete屬性,而像User.objects.all()這樣的查詢將不會返回已刪除的模型。

您仍然可以使用特殊管理器查詢所有對象。 例如, User.objects.all_with_deleted()將返回所有用戶,包括已刪除的用戶。 User.objects.deleted_only()將返回已刪除的。

除了一種情況外,這可以按預期工作。 我正在為Django Rest Framework 3.9的用戶使用令牌身份驗證,在我的DRF視圖中,我使用的是內置權限IsAuthenticated

我正在使用的基本CBV代碼:

class MyView(APIView):

    permission_classes = (IsAuthenticated,)

    def get(self, request):
        return Response(status=HTTP_200_OK)

IsAuthenticated權限的DRF實現代碼:

class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_authenticated)

問題

當用戶被軟刪除時,他仍然可以使用其令牌進行身份驗證。

我希望用戶在軟刪除時有401 Unauthorized錯誤。 怎么了?

為什么?

如果我們查看DRF TokenAuthentication [source-code]authenticate_credentials()方法,我們可以看到,

 def authenticate_credentials(self, key): model = self.get_model() try: token = model.objects.select_related('user').get(key=key) except model.DoesNotExist: raise exceptions.AuthenticationFailed(_('Invalid token.')) if not token.user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (token.user, token) 

這表示它沒有過濾掉軟刪除的用戶實例

解?

在相應的視圖中創建自定義身份驗證類和連線

# authentication.py
from rest_framework.authentication import TokenAuthentication, exceptions, _


class CustomTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        model = self.get_model()
        try:
            token = model.objects.select_related('user').get(key=key)
        except model.DoesNotExist:
            raise exceptions.AuthenticationFailed(_('Invalid token.'))

        if not token.user.is_active or not token.user.deleted: # Here I added something new !!
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

        return (token.user, token)

和視圖中的連線

# views.py
from rest_framework.views import APIView


class MyView(APIView):
    authentication_classes = (CustomTokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get(self, request):
        return Response(status=HTTP_200_OK)

DRF已使用is_active屬性來確定用戶是否能夠進行身份驗證。 每當您刪除用戶時,只需確保同時將is_activeFalse

對於django-safedelete:

由於您使用的是django-safedelete ,因此您必須覆蓋delete()方法以取消激活,然后使用super()來執行原始行為,例如:

class MyUserModel(SafeDeleteModel):
    _safedelete_policy = SOFT_DELETE
    my_field = models.TextField()

    def delete(self, *args, **kwargs):
        self.is_active = False
        super().delete(*args, **kwargs)

    def undelete(self, *args, **kwargs):
        self.is_active = True
        super().undelete(*args, **kwargs)

請注意,這也適用於QuerySets,因為SafeDeleteModel的管理器會覆蓋QuerySet delete()方法。 (參見: https//github.com/makinacorpus/django-safedelete/blob/master/safedelete/queryset.py

此解決方案的好處是您不必在每個APIView上更改auth類,並且任何依賴User模型的is_active屬性的應用程序都將表現得非常好。 另外,如果你不這樣做,那么你將刪除同樣活躍的對象,因此沒有多大意義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM