You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

django-allauth是否支持OIDC退信式登出?自定义实现无效求助

解决Django-allauth OIDC Backchannel Logout无效的问题

你的核心问题在于只删除了自定义的UserSession模型记录,但Django的用户登录状态依赖内置的Session模型,以及可能的缓存会话存储,直接删自定义模型不会让用户的登录会话失效。此外,宽泛的异常捕获会掩盖具体错误,导致你无法定位问题。

修正后的实现步骤:

  1. 替换会话查询逻辑,操作Django内置Session模型
    Django的登录会话存储在django.contrib.sessions.models.Session中,需要通过用户ID关联找到所有会话并删除:

    from django.contrib.sessions.models import Session
    from django.contrib.auth import get_user_model
    from allauth.socialaccount.models import SocialAccount, SocialToken
    import jwtkit
    
    @require_POST
    @login_not_required
    def backchannel_logout(request, provider_id):
        logout_token = request.POST.get("logout_token")
        if not logout_token:
            return HttpResponse("Missing logout_token", status=400)
        
        try:
            openid_adapter = MyCustomOpenIDAdapter(request, provider_id)
            openid_config = openid_adapter.openid_config
            identity_data = jwtkit.verify_and_decode(
                credential=logout_token,
                keys_url=openid_config["jwks_uri"],
                issuer=openid_config["issuer"],
                audience=[openid_adapter.get_provider().app.client_id],
                lookup_kid=jwtkit.lookup_kid_jwk,
            )
            sub = identity_data["sub"]
    
            # 通过sub找到关联的用户
            social_account = SocialAccount.objects.get(uid=sub)
            user = social_account.user
            User = get_user_model()
    
            # 找到该用户的所有Django会话
            user_sessions = []
            for session in Session.objects.all():
                try:
                    session_data = session.get_decoded()
                    if session_data.get('_auth_user_id') == str(user.id):
                        user_sessions.append(session)
                except Exception:
                    continue
    
            # 删除会话记录
            for session in user_sessions:
                session.delete()
    
            # 可选:吊销用户的Social Token(如果需要完全终止OIDC关联)
            SocialToken.objects.filter(account__user=user).delete()
    
            return HttpResponse("Backchannel logout successful", status=200)
        
        # 捕获具体异常,便于调试
        except SocialAccount.DoesNotExist:
            return HttpResponse("Associated user not found", status=404)
        except jwtkit.InvalidTokenError as e:
            return HttpResponse(f"Invalid logout token: {str(e)}", status=400)
        except Exception as e:
            return HttpResponse(f"Backchannel logout failed: {str(e)}", status=500)
    
  2. 处理缓存会话存储(如果启用)
    如果你的Django配置了SESSION_ENGINE = 'django.contrib.sessions.backends.cache'或cached_db,需要额外清理缓存中的会话:

    from django.core.cache import cache
    
    # 在删除数据库会话后添加:
    for session in user_sessions:
        cache.delete(f"django.contrib.sessions.cache.{session.session_key}")
    
  3. 排查手动删除会话仍能访问Admin的问题
    手动删Session后用户还能访问Admin,通常是因为:

    • 浏览器缓存了会话Cookie:可以强制浏览器清除Cookie,或者设置SESSION_EXPIRE_AT_BROWSER_CLOSE = True(在settings.py中)
    • 会话存储在缓存而非数据库:确保同时清理缓存中的会话记录
    • Admin使用了持久化会话:检查SESSION_COOKIE_AGE配置,确保会话过期时间合理

内容的提问来源于stack exchange,提问作者Harold Holsappel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:57:23