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

使用mozilla-django-oidc对接Keycloak时DRF授权问题求助

解决Keycloak + Django + DRF 401未授权问题

核心问题分析

你遇到的问题本质是:mozilla-django-oidc 默认基于HttpOnly Session Cookie实现认证(SPA无法读取),但DRF接口需要通过请求头携带Bearer Access Token才能授权。要解决这个问题,需要从「让SPA获取Access Token」和「让DRF支持Token认证」两方面入手。


步骤1:自定义OIDC回调视图,返回Access Token给SPA

默认的OIDC回调只会处理Session登录并重定向,我们需要修改回调逻辑,在登录成功后把Access Token传递给SPA:

1.1 编写自定义回调视图

from mozilla_django_oidc.views import OIDCAuthenticationCallbackView
from django.http import JsonResponse, HttpResponseRedirect

class CustomOIDCAuthenticationCallbackView(OIDCAuthenticationCallbackView):
    def get(self, request, *args, **kwargs):
        # 执行默认的OIDC登录逻辑
        response = super().get(request, *args, **kwargs)
        
        # 从Session中取出OIDC返回的Token(mozilla-django-oidc会自动存在这里)
        access_token = request.session.get("oidc_access_token")
        refresh_token = request.session.get("oidc_refresh_token")
        
        # 区分SPA的AJAX请求和普通页面请求
        if request.headers.get("X-Requested-With") == "XMLHttpRequest":
            # AJAX请求直接返回Token JSON
            return JsonResponse({
                "access_token": access_token,
                "refresh_token": refresh_token,
                "user_info": {
                    "username": request.user.username,
                    "email": request.user.email
                }
            })
        else:
            # 普通重定向:用Hash模式传递Token(避免URL被服务器日志记录)
            redirect_url = f"{self.success_url}#access_token={access_token}&refresh_token={refresh_token}"
            return HttpResponseRedirect(redirect_url)

1.2 替换默认的回调路由

在urls.py中替换原有的OIDC回调路由:

from django.urls import path
from .views import CustomOIDCAuthenticationCallbackView

urlpatterns = [
    # ... 其他路由
    path("oidc/callback/", CustomOIDCAuthenticationCallbackView.as_view(), name="oidc_authentication_callback"),
]

步骤2:配置DRF支持OIDC Token认证

让DRF同时支持Session认证(给常规视图)和OIDC Bearer Token认证(给API接口):

在settings.py中修改DRF配置:

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.SessionAuthentication",
        "mozilla_django_oidc.contrib.drf.OIDCAuthentication",  # 添加Token认证类
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ]
}

步骤3:Keycloak客户端配置检查

确保你的Keycloak客户端配置符合SPA场景:

  • 访问类型:设置为public(SPA属于公共客户端,无法安全存储Client Secret)
  • 授权流程:开启Authorization Code Flow并勾选Proof Key for Code Exchange (PKCE)
  • 有效重定向URI:添加Django的回调地址(如http://your-django-domain/oidc/callback/)和SPA的登录回调地址
  • Web Origins:添加SPA的域名(如http://localhost:3000),允许跨域请求
  • Direct Access Grants:不需要开启(我们用授权码流程)

步骤4:SPA端的Token处理

  1. 登录流程:跳转到Keycloak的授权端点,使用授权码流程+PKCE完成登录,回调到Django的自定义视图获取Token
  2. Token存储:将Access Token存在sessionStorage(比localStorage更安全,关闭标签页即失效),Refresh Token可以存在HttpOnly Cookie(需要Django配合)或加密存储
  3. API请求:每次请求DRF接口时,在请求头中添加:
    Authorization: Bearer ${accessToken}
    

步骤5:Token刷新机制

为了避免用户频繁登录,实现Refresh Token刷新Access Token的逻辑:

5.1 Django端添加刷新接口

from django.http import JsonResponse
from mozilla_django_oidc.utils import refresh_token
from django.contrib.auth.decorators import login_required

@login_required
def refresh_access_token(request):
    # 用Session中的Refresh Token获取新的Token
    new_tokens = refresh_token(request)
    if new_tokens:
        return JsonResponse({
            "access_token": new_tokens.get("access_token"),
            "refresh_token": new_tokens.get("refresh_token")
        })
    return JsonResponse({"error": "Token刷新失败"}, status=400)

5.2 SPA端调用刷新接口

当Access Token过期时,调用Django的刷新接口(携带Session Cookie),获取新的Access Token后继续请求API。


步骤6:配置Django跨域支持

如果SPA和Django不在同一域名,需要安装django-cors-headers并配置:

# settings.py
INSTALLED_APPS = [
    # ...
    "corsheaders",
]

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    # ... 其他中间件
]

CORS_ALLOWED_ORIGINS = [
    "http://your-spa-domain.com",
    "http://localhost:3000",  # 开发环境
]

CORS_ALLOW_CREDENTIALS = True  # 允许请求携带Cookie

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 13:24:53