fix: satisfy auth persistence type checks

This commit is contained in:
Estrella Pan
2026-07-10 08:35:19 +02:00
parent 42ccb7611b
commit 52e640cfd5
4 changed files with 32 additions and 15 deletions

View File

@@ -34,6 +34,12 @@ AuthService = Annotated[AuthenticationService, Depends(get_auth_service)]
_GENERIC_ERROR = "Internal server error."
def _require_user_id(user: User) -> int:
if user.id is None:
raise RuntimeError("Persisted user has no primary key")
return user.id
def _get_webauthn_from_request(request: Request):
"""
从请求中构造 WebAuthnService
@@ -91,12 +97,13 @@ async def get_registration_options(
raise HTTPException(status_code=404, detail="User not found")
# Get existing passkeys
user_id = _require_user_id(user)
passkey_db = PasskeyDatabase(session)
existing_passkeys = await passkey_db.get_passkeys_by_user_id(user.id)
existing_passkeys = await passkey_db.get_passkeys_by_user_id(user_id)
options = webauthn.generate_registration_options(
username=username,
user_id=user.id,
user_id=user_id,
existing_passkeys=existing_passkeys,
)
@@ -201,8 +208,9 @@ async def get_passkey_login_options(
passkeys = []
if user:
user_id = _require_user_id(user)
passkey_db = PasskeyDatabase(session)
passkeys = await passkey_db.get_passkeys_by_user_id(user.id)
passkeys = await passkey_db.get_passkeys_by_user_id(user_id)
if not user or not passkeys:
# Same response whether the username doesn't exist or simply
@@ -283,7 +291,7 @@ async def list_passkeys(username: str = Depends(get_current_user)):
raise HTTPException(status_code=404, detail="User not found")
passkey_db = PasskeyDatabase(session)
passkeys = await passkey_db.get_passkeys_by_user_id(user.id)
passkeys = await passkey_db.get_passkeys_by_user_id(_require_user_id(user))
return [passkey_db.to_list_model(pk) for pk in passkeys]
@@ -311,7 +319,9 @@ async def delete_passkey(
raise HTTPException(status_code=404, detail="User not found")
passkey_db = PasskeyDatabase(session)
await passkey_db.delete_passkey(delete_data.passkey_id, user.id)
await passkey_db.delete_passkey(
delete_data.passkey_id, _require_user_id(user)
)
return JSONResponse(
status_code=200,

View File

@@ -60,7 +60,7 @@ class AuthDatabase:
result = await self.session.execute(
select(AuthSession).where(
AuthSession.token_hash == _hash_token(raw_token),
AuthSession.revoked_at.is_(None),
col(AuthSession.revoked_at).is_(None),
)
)
auth_session = result.scalars().first()
@@ -100,7 +100,7 @@ class AuthDatabase:
result = await self.session.execute(
select(AuthSession).where(
AuthSession.token_hash == _hash_token(raw_token),
AuthSession.revoked_at.is_(None),
col(AuthSession.revoked_at).is_(None),
)
)
auth_session = result.scalars().first()
@@ -118,7 +118,7 @@ class AuthDatabase:
result = await self.session.execute(
select(AuthSession).where(
AuthSession.user_id == user_id,
AuthSession.revoked_at.is_(None),
col(AuthSession.revoked_at).is_(None),
)
)
sessions = list(result.scalars().all())
@@ -200,7 +200,7 @@ class AuthDatabase:
select(ApiToken).where(
ApiToken.token_hash == _hash_token(raw_token),
ApiToken.scope == scope,
ApiToken.revoked_at.is_(None),
col(ApiToken.revoked_at).is_(None),
)
)
token = result.scalars().first()
@@ -236,8 +236,12 @@ class AuthDatabase:
async def purge_user_credentials(self, user_id: int) -> None:
"""Remove credentials before deleting their owning user."""
await self.session.execute(
delete(AuthSession).where(AuthSession.user_id == user_id)
delete(AuthSession).where(col(AuthSession.user_id) == user_id)
)
await self.session.execute(
delete(ApiToken).where(col(ApiToken.user_id) == user_id)
)
await self.session.execute(
delete(Passkey).where(col(Passkey.user_id) == user_id)
)
await self.session.execute(delete(ApiToken).where(ApiToken.user_id == user_id))
await self.session.execute(delete(Passkey).where(Passkey.user_id == user_id))
await self.session.commit()

View File

@@ -65,7 +65,7 @@ class UserDatabase:
async def _enabled_count(self) -> int:
result = await self.session.execute(
select(func.count()).select_from(User).where(User.enabled.is_(True))
select(func.count()).select_from(User).where(col(User.enabled).is_(True))
)
return int(result.scalar_one())

View File

@@ -62,8 +62,11 @@ class SessionTokenRepository(Protocol):
class AuthUnitOfWork(Protocol):
user: UserRepository
auth: SessionTokenRepository
@property
def user(self) -> UserRepository: ...
@property
def auth(self) -> SessionTokenRepository: ...
async def __aenter__(self) -> Self: ...