Files
deerflow-code/offline-backend-20260512/backend/packages/harness/deerflow/config/login_config.py
T
AdministratorandClaude Opus 4.8 e1e9be8daa fix(auth): token 登录将令牌放入 Authorization: Bearer 头
token 换登录调上游 getTokenInfo 时参数传错:原来发静态头
Authorization: Bearer admin + 令牌放 access_token cookie。上游实际
从 Authorization: Bearer <token> 头读取令牌。

- 鉴权头改为 "Bearer "+前端传入 token,删除 access_token cookie
- service_authorization 配置项弃用(保留兼容,不再参与请求)
- 新增回归测试 test_token_login_upstream_call.py
- 同步更新 AUTH_LOGIN.md / CLAUDE.md / config.yaml 注释 / login_config 文档

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 19:33:38 +08:00

84 lines
3.0 KiB
Python

from pydantic import BaseModel, Field
# Fallback shared password for the username-login gate. Used when
# ``UsernameLoginConfig.password`` is left empty but ``require_password`` is on.
DEFAULT_USERNAME_LOGIN_PASSWORD = "123ewq"
class UsernameLoginConfig(BaseModel):
"""Gate for the passwordless ``POST /api/v1/auth/login/username`` flow.
By default this flow logs a user in (auto-registering if needed) from a
username alone — convenient, but it lets anyone sign in as any username.
Turning ``require_password`` on forces callers to additionally pass a
shared secret as ``?password=...``; mismatches are rejected with 401.
"""
require_password: bool = Field(
default=False,
description="When true, login/username requires a matching ?password= query value.",
)
password: str = Field(
default="",
description=f"Shared secret for the username-login gate. Empty falls back to '{DEFAULT_USERNAME_LOGIN_PASSWORD}'.",
)
@property
def effective_password(self) -> str:
"""The password actually checked at login time (config value or default)."""
return self.password or DEFAULT_USERNAME_LOGIN_PASSWORD
class TokenLoginConfig(BaseModel):
"""Token-exchange login.
The frontend passes an upstream access token via the URL. The gateway calls
``token_info_url`` with that token placed directly in the
``Authorization: Bearer <token>`` header, reads ``data.username`` from the
response, then signs the matching local user in (auto-registering if the
username is not yet in the database).
"""
enabled: bool = Field(
default=False,
description="Master switch for the POST /api/v1/auth/login/token endpoint.",
)
token_info_url: str = Field(
default="",
description="Upstream endpoint that resolves an access token to a username.",
)
service_authorization: str = Field(
default="Bearer admin",
description=(
"Deprecated/unused: the Authorization header is now built from the "
"caller's token as 'Bearer <token>'. Retained for backward compat."
),
)
timeout_seconds: float = Field(
default=10.0,
gt=0,
description="HTTP timeout (seconds) for the token_info_url call.",
)
verify_ssl: bool = Field(
default=True,
description=(
"Whether to verify the upstream TLS certificate. Set false for "
"internal/UAT hosts with self-signed or private-CA certs. Leave "
"true in production."
),
)
ca_cert_path: str = Field(
default="",
description=(
"Optional path to a CA bundle (PEM) used to verify the upstream "
"certificate. Takes precedence over verify_ssl when set."
),
)
class AuthLoginConfig(BaseModel):
"""Container for the custom login modes layered on top of the base auth."""
username_login: UsernameLoginConfig = Field(default_factory=UsernameLoginConfig)
token_login: TokenLoginConfig = Field(default_factory=TokenLoginConfig)