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

Django无法识别经Keycloak前端登录的已认证用户求助

解决方案:通过Keycloak令牌让Django认证并创建会话

你的问题核心是:mozilla-django-oidc默认基于浏览器会话的OIDC授权码流程,而前端单独登录拿到的是Bearer令牌,Django默认不会自动识别并验证这种令牌,也不会为其创建会话。要解决这个问题,需要扩展Django的认证逻辑,让它能处理前端传来的Bearer令牌,同时创建Django会话。

步骤1:扩展OIDC认证后端,支持Bearer令牌验证

自定义一个认证后端,继承mozilla_django_oidc的默认后端,添加对Bearer令牌的处理逻辑:

from mozilla_django_oidc.auth import OIDCAuthenticationBackend
import requests
from django.conf import settings

class KeycloakBearerAuthBackend(OIDCAuthenticationBackend):
    def authenticate(self, request, **kwargs):
        # 优先处理Bearer令牌
        auth_header = request.META.get('HTTP_AUTHORIZATION')
        if auth_header and auth_header.startswith('Bearer '):
            token = auth_header.split(' ')[1]
            # 调用Keycloak的令牌 introspect 端点验证有效性
            introspect_url = (
                f"{settings.OIDC_OP_AUTHORIZATION_ENDPOINT.split('/auth')[0]}"
                f"/auth/realms/{settings.OIDC_RP_REALM_NAME}"
                "/protocol/openid-connect/token/introspect"
            )
            payload = {
                'token': token,
                'client_id': settings.OIDC_RP_CLIENT_ID,
                'client_secret': settings.OIDC_RP_CLIENT_SECRET,
            }
            # 发送验证请求
            response = requests.post(introspect_url, data=payload, timeout=5)
            token_data = response.json()

            if token_data.get('active'):
                # 通过令牌获取用户信息
                user_info = self.get_userinfo(token, None)
                # 创建或关联Django用户
                user = self.get_or_create_user(user_info, token_data)
                if user:
                    # 将令牌存入会话,维持登录状态
                    request.session['oidc_access_token'] = token
                    return user
        # 回退到默认的OIDC授权码流程(适配浏览器访问Django视图的场景)
        return super().authenticate(request, **kwargs)

步骤2:配置Django使用自定义认证后端

在settings.py中替换默认的认证后端:

AUTHENTICATION_BACKENDS = [
    'your_app.backends.KeycloakBearerAuthBackend',  # 自定义后端优先
    'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
]

# 补充Keycloak Realm配置(如果之前没加)
OIDC_RP_REALM_NAME = 'your-keycloak-realm'

步骤3:添加中间件自动处理Bearer令牌认证

自定义中间件,在请求到达视图前自动尝试用Bearer令牌认证用户:

from django.contrib.auth import authenticate

class BearerAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 仅对未认证用户尝试Bearer令牌认证
        if not request.user.is_authenticated:
            user = authenticate(request)
            if user:
                request.user = user
        response = self.get_response(request)
        return response

然后在settings.py的MIDDLEWARE中添加该中间件(放在SessionMiddleware之后,AuthenticationMiddleware之前):

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'your_app.middlewares.BearerAuthMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    ...
]

步骤4:前端请求携带Bearer令牌

在Vue3中,用keycloak-js获取令牌后,给所有请求添加Authorization头:

import Keycloak from 'keycloak-js'
import axios from 'axios'

// 初始化Keycloak
const keycloak = new Keycloak({
  url: 'http://your-keycloak-domain/auth',
  realm: 'your-realm',
  clientId: 'vue-frontend-client'
})

await keycloak.init({ onLoad: 'login-required' })

// 全局请求拦截器,自动携带令牌
axios.interceptors.request.use(config => {
  if (keycloak.token) {
    config.headers.Authorization = `Bearer ${keycloak.token}`
  }
  return config
})

// 处理令牌过期
keycloak.onTokenExpired = () => {
  keycloak.updateToken(5).catch(() => {
    keycloak.logout()
  })
}

关键注意事项

  • Keycloak客户端权限:确保Django对应的Keycloak客户端开启了"Service Accounts Enabled",并且有权限访问introspect端点。
  • CORS配置:Django需要允许前端域名的跨域请求,可通过django-cors-headers配置,同时如果需要携带会话cookie,要设置CORS_ALLOW_CREDENTIALS = True。
  • 令牌过期处理:前端要监听令牌过期事件,自动刷新令牌;Django在验证令牌时如果发现已过期,会返回401,前端需触发重新登录。
  • 会话维持:认证通过后,Django会自动创建会话,后续请求可以选择继续携带Bearer令牌,或者通过会话cookie维持登录状态(需前端请求时设置withCredentials: true)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 06:45:14