[英]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
。
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_active
为False
。
由于您使用的是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.