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
相关产品推荐
相关产品推荐

