refactor: 统一认证端点并删除冗余 profile 模块

- 合并 auth 端点: /verifications/verify → /verify, /verifications/resend → /resend
- 整合密码重置到 /verify 端点 (type=recovery)
- 移除未使用的 /auth/users 端点
- 添加 redirect URL 白名单验证 (site_url + additional_redirect_urls)
- 限流改用 Redis + IP 标识,替代内存锁
- 删除 v1/profile 死代码模块
- 更新前端 auth_api 适配新端点
- 添加 supabase site_url 和 additional_redirect_urls 配置
This commit is contained in:
zl-q
2026-03-07 14:55:00 +08:00
parent 1f6cb1a48f
commit ec33bb0cee
25 changed files with 421 additions and 1614 deletions
+20 -50
View File
@@ -5,6 +5,8 @@ import pytest
import v1.auth.gateway as auth_gateway_module
from v1.auth.schemas import (
AuthUser,
PasswordResetConfirmRequest,
PasswordResetRequest,
SessionCreateRequest,
SessionRefreshRequest,
SessionResponse,
@@ -44,40 +46,15 @@ class FakeGateway(AuthServiceGateway):
return None
async def get_user_by_email(self, email: str) -> UserByEmailResponse:
return UserByEmailResponse(
id="user-1",
email=email,
created_at="2026-02-24T00:00:00Z",
email_confirmed_at=None,
)
raise NotImplementedError
async def request_password_reset(self, request: PasswordResetRequest) -> None:
raise NotImplementedError
@pytest.mark.asyncio
async def test_signup_maps_response() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
token_type="bearer",
user=user,
)
service = AuthService(gateway=FakeGateway(token_response))
start_result = await service.create_verification(
VerificationCreateRequest(
username="demo", email="user@example.com", password="secret123"
)
)
assert start_result.email == "user@example.com"
result = await service.verify_verification(
VerificationVerifyRequest(email="user@example.com", token="123456")
)
assert result.access_token == "access"
assert result.refresh_token == "refresh"
assert result.user.id == "user-1"
async def confirm_password_reset(
self, request: PasswordResetConfirmRequest
) -> None:
raise NotImplementedError
class LogoutAssertingGateway(AuthServiceGateway):
@@ -109,6 +86,14 @@ class LogoutAssertingGateway(AuthServiceGateway):
async def get_user_by_email(self, email: str) -> UserByEmailResponse:
raise NotImplementedError
async def request_password_reset(self, request: PasswordResetRequest) -> None:
raise NotImplementedError
async def confirm_password_reset(
self, request: PasswordResetConfirmRequest
) -> None:
raise NotImplementedError
@pytest.mark.asyncio
async def test_logout_forwards_refresh_token() -> None:
@@ -117,23 +102,6 @@ async def test_logout_forwards_refresh_token() -> None:
await service.delete_session("refresh-token")
@pytest.mark.asyncio
async def test_get_user_by_email_forwards_to_gateway() -> None:
user = AuthUser(id="user-1", email="user@example.com")
token_response = SessionResponse(
access_token="access",
refresh_token="refresh",
expires_in=3600,
token_type="bearer",
user=user,
)
service = AuthService(gateway=FakeGateway(token_response))
result = await service.get_user_by_email("user@example.com")
assert result.email == "user@example.com"
@pytest.mark.asyncio
async def test_signup_resend_returns_none() -> None:
user = AuthUser(id="user-1", email="user@example.com")
@@ -182,7 +150,9 @@ async def test_supabase_signup_passes_username_in_metadata(
class FakeClient:
auth = FakeSupabaseAuth()
monkeypatch.setattr(auth_gateway_module, "create_client", lambda *_: FakeClient())
monkeypatch.setattr(
auth_gateway_module.supabase_service, "get_client", lambda: FakeClient()
)
gateway = auth_gateway_module.SupabaseAuthGateway()
await gateway.create_verification(