如何允许非活跃用户登录并通过/user/端点实现自助账号激活
嘿,你已经搞定了非活跃用户登录和JWT获取的核心部分,剩下的就是精准控制权限啦!咱们来一步步解决这个问题:
问题根源
你遇到的/user/端点报错,是因为默认的IsAuthenticated权限类(或者rest-auth自带的用户详情视图)会隐性检查用户是否活跃——哪怕你已经让他们登录拿到了JWT。咱们需要给这个特定端点开个“后门”,同时把其他认证端点的权限锁死。
解决方案步骤
1. 自定义权限类,实现“仅允许非活跃用户访问自己的详情页”
在你的app里新建permissions.py,写一个针对性的权限类:
from rest_framework.permissions import IsAuthenticated from rest_auth.views import UserDetailsView class AllowInactiveSelfActivation(IsAuthenticated): def has_permission(self, request, view): # 先确保用户已通过JWT认证 is_authenticated = super().has_permission(request, view) if not is_authenticated: return False # 核心规则:只有访问的是用户详情页,且是访问自己的账号时,允许非活跃用户 if isinstance(view, UserDetailsView) and request.user == view.get_object(): return True # 其他所有认证端点,必须是活跃用户才能访问 return request.user.is_active
2. 替换rest-auth的默认用户详情视图
rest-auth自带的UserDetailsView用的是默认权限,咱们需要继承它并替换权限类。在你的app的views.py里:
from rest_auth.views import UserDetailsView from .permissions import AllowInactiveSelfActivation class CustomUserDetailsView(UserDetailsView): permission_classes = [AllowInactiveSelfActivation]
然后在urls.py里把原来的rest-auth用户路由替换成咱们自定义的视图:
from django.urls import path from .views import CustomUserDetailsView urlpatterns = [ # 替换原rest-auth的/user/路由 path('user/', CustomUserDetailsView.as_view(), name='rest_user_details'), # 其他你的自定义认证端点,保持用默认的IsAuthenticated权限 path('my-custom-endpoint/', MyCustomAuthenticatedView.as_view(), name='custom_endpoint'), ]
3. 加固UserDetailSerializer的逻辑(可选但推荐)
为了防止用户恶意修改其他字段或者误操作,在你的自定义UserDetailSerializer里可以加个校验,确保用户只能修改is_active字段来激活自己:
from rest_framework import serializers from django.contrib.auth import get_user_model User = get_user_model() class UserDetailSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('id', 'username', 'email', 'is_active') # 你的字段列表 read_only_fields = ('id', 'username', 'email') # 把不需要修改的字段设为只读 def update(self, instance, validated_data): # 只允许用户将自己的is_active从False改为True(激活) if 'is_active' in validated_data: if not instance.is_active and validated_data['is_active'] is True: instance.is_active = True instance.save() # 如果用户想停用自己,直接报错拦截 elif validated_data['is_active'] is False: raise serializers.ValidationError({"detail": "You cannot deactivate your own account."}) return instance
效果验证
- 非活跃用户登录后,访问
/user/可以正常获取自己的信息,并且能通过PUT请求修改is_active为true来激活账号; - 非活跃用户访问其他需要认证的自定义端点时,会返回
403 Forbidden; - 活跃用户可以正常访问所有认证端点。
内容的提问来源于stack exchange,提问作者Peter Sobhi
相关产品推荐
相关产品推荐

