如何判断Django admin登录状态并实现双端登录注销态双向同步
问题根源
你当前的登录状态依赖两套体系:
- Django原生Session:给Admin后台登录使用
- DRF Token:给落地页前端登录使用
你自己实现的落地页登录逻辑同时完成了「生成Session」和「创建/获取Token」两个操作,所以从落地页登录后Admin可以直接用Session访问。但Django自带的Admin登录/注销逻辑只处理Session,不会处理Token,因此才会出现单向同步的问题。
解决方案
1. 实现登录双向同步
我们用Django内置的user_logged_in信号监听所有登录成功事件,不管是落地页还是Admin入口登录,都自动生成Token:
- 在你的App下新建
signals.py,添加如下代码:
from django.contrib.auth.signals import user_logged_in, user_logged_out from django.dispatch import receiver from rest_framework.authtoken.models import Token # 监听所有登录成功事件,自动生成Token @receiver(user_logged_in) def generate_token_after_login(sender, request, user, **kwargs): Token.objects.get_or_create(user=user)
- 注册信号,修改你App的
apps.py:
from django.apps import AppConfig class 你的App名Config(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = '你的App名' def ready(self): import 你的App名.signals
- 在
settings.py的INSTALLED_APPS中,把你的App配置修改为上面的AppConfig:
INSTALLED_APPS = [ # 替换原来的你的App名条目 '你的App名.apps.你的App名Config', # 其他原有配置... ]
- 落地页前端同步登录状态:在落地页的首页接口/视图中,判断如果用户已经通过Session认证(即Admin登录过的状态),直接返回Token给前端存储即可:
# 落地页视图示例 def landing_index(request): token = '' if request.user.is_authenticated: token_obj, _ = Token.objects.get_or_create(user=request.user) token = token_obj.key # 模板渲染时把token传给前端,或者接口返回给前端存入localStorage return render(request, 'index.html', {'token': token})
2. 实现注销双向同步
同样用user_logged_out信号监听所有注销事件,注销时自动删除对应Token:
- 在之前的
signals.py中追加注销信号处理逻辑:
# 监听所有注销成功事件,自动删除Token @receiver(user_logged_out) def delete_token_after_logout(sender, request, user, **kwargs): if user: Token.objects.filter(user=user).delete()
- 修复你现有注销接口的错误逻辑:你当前的注销代码不需要传入用户名密码,也不需要调用
update_session_auth_hash(该方法仅用于修改密码后刷新Session,注销场景不需要),修改后代码如下:
@api_view(['POST']) @authentication_classes((TokenAuthentication,)) @permission_classes((IsAuthenticated,)) def logout(request): try: # 调用auth.logout会自动触发user_logged_out信号,删除Token auth.logout(request) return Response({"status": STATUS['SUCCESS'], "message": MESSAGE_SUCCESS['LOGOUT']}, status=status.HTTP_200_OK) except: return Response({"status": STATUS['ERROR'], "message": MESSAGE_ERROR['LOGOUT']}, status=status.HTTP_200_OK)
3. 可选:前端本地存储同步
如果你的落地页前端把Token存在localStorage中,Admin注销后前端本地还会留存旧Token,可添加一个中间件处理这种场景:
# 新建middleware.py from rest_framework.authtoken.models import Token from django.http import JsonResponse class SyncAuthMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): auth_header = request.META.get('HTTP_AUTHORIZATION', '') if auth_header.startswith('Token '): token_key = auth_header.split(' ')[1] token = Token.objects.filter(key=token_key).first() # Token存在但Session已失效,说明用户从Admin端注销 if token and not request.user.is_authenticated: token.delete() return JsonResponse({"status": "error", "message": "登录已失效"}, status=401) return self.get_response(request)
把该中间件添加到settings.py的MIDDLEWARE列表中,放在django.contrib.sessions.middleware.SessionMiddleware之后即可。前端收到401状态码时自动清除本地存储的Token和登录状态。
内容的提问来源于stack exchange,提问作者Prajna
相关产品推荐
相关产品推荐

