fix(oidc): OIDC 端点禁用 DRF 默认 JWT 认证,修复 userinfo 401

DRF CustomJWTAuthentication 会把 Gitea 回传的 RS256 id_token 当 simplejwt token 解析失败返回 401;全部 OIDC 视图 authentication_classes=[],token/userinfo 各自自行校验凭据
This commit is contained in:
TermiNexus committed 2026-08-11 16:49:59 +08:00
1 parent 0b3620223c
commit 39e231bfbf
1 file changed
+19 -5
+19 -5
View File
@@ -44,6 +44,15 @@ from gvsds import secrets as app_secrets
logger = logging.getLogger(__name__)
# === OIDC 视图公共设置 ===
# 全部端点不启用 DRF 默认认证(CustomJWTAuthentication 会把 OIDC 签发的 RS256
# id_token 当作 simplejwt token 解析失败而 401)。token 端点自行校验 client 凭据,
# userinfo 自行校验 Bearer id_token,authorize 自行读取 GERP AccessToken Cookie。
OIDC_VIEW_KWARGS = {
'authentication_classes': [],
'permission_classes': [AllowAny],
}
# === 一次性授权码存储(进程内存) ===
_AUTH_CODE_TTL = 600 # code 有效期 10 分钟
_AUTH_CODE_STORE = {} # code -> {"user_uuid": str, "nonce": str|None, "exp": float}
@@ -205,7 +214,8 @@ def _BuildIdToken(user, gitea, nonce=None):
class OIDCDiscoveryView(APIView):
"""OIDC Discovery 文档(/.well-known/openid-configuration)。"""
permission_classes = [AllowAny]
def __init__(self, **kwargs):
super().__init__(**{**OIDC_VIEW_KWARGS, **kwargs})
def get(self, request):
base = _Issuer()
@@ -230,7 +240,8 @@ class OIDCDiscoveryView(APIView):
class OIDCAuthorizeView(APIView):
"""授权端点:校验 GERP 会话 → 签发一次性 code → 302 回 Gitea callback。"""
permission_classes = [AllowAny]
def __init__(self, **kwargs):
super().__init__(**{**OIDC_VIEW_KWARGS, **kwargs})
def get(self, request):
client_id = request.query_params.get('client_id', '')
@@ -290,7 +301,8 @@ class OIDCAuthorizeView(APIView):
class OIDCTokenView(APIView):
"""Token 端点:client 凭据认证 + code 换 id_token。"""
permission_classes = [AllowAny]
def __init__(self, **kwargs):
super().__init__(**{**OIDC_VIEW_KWARGS, **kwargs})
def _CheckClientAuth(self, request):
"""校验 client_id + client_secret(Basic 头或 POST body)。"""
@@ -349,7 +361,8 @@ class OIDCTokenView(APIView):
class OIDCJwksView(APIView):
"""JWKS 端点:返回 RSA 公钥供 Gitea 校验 id_token 签名。"""
permission_classes = [AllowAny]
def __init__(self, **kwargs):
super().__init__(**{**OIDC_VIEW_KWARGS, **kwargs})
def get(self, request):
return Response({'keys': [_GetPublicJwk()]})
@@ -358,7 +371,8 @@ class OIDCJwksView(APIView):
class OIDCUserInfoView(APIView):
"""UserInfo 端点(Bearer id_token/access_token)。"""
permission_classes = [AllowAny]
def __init__(self, **kwargs):
super().__init__(**{**OIDC_VIEW_KWARGS, **kwargs})
def get(self, request):
auth = request.META.get('HTTP_AUTHORIZATION', '')