From 39e231bfbf2fd37aaf8dbe0542f6810af72a7140 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 11 Aug 2026 16:49:59 +0800 Subject: [PATCH] =?UTF-8?q?fix(oidc):=20OIDC=20=E7=AB=AF=E7=82=B9=E7=A6=81?= =?UTF-8?q?=E7=94=A8=20DRF=20=E9=BB=98=E8=AE=A4=20JWT=20=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=20userinfo=20401?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DRF CustomJWTAuthentication 会把 Gitea 回传的 RS256 id_token 当 simplejwt token 解析失败返回 401;全部 OIDC 视图 authentication_classes=[],token/userinfo 各自自行校验凭据 --- gvsds/apps/gerp/oidc.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/gvsds/apps/gerp/oidc.py b/gvsds/apps/gerp/oidc.py index b6dc9421..06b85eac 100644 --- a/gvsds/apps/gerp/oidc.py +++ b/gvsds/apps/gerp/oidc.py @@ -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', '')