Initial FastAPI admin auth scaffold

This commit is contained in:
2026-06-05 17:10:30 +08:00
commit 5635da9ea5
65 changed files with 1407 additions and 0 deletions

View File

@@ -0,0 +1 @@
"""Admin services."""

View File

@@ -0,0 +1,15 @@
from app.common.context import current_admin_id
from app.exception.err_exception import ErrException
from app.lib.response.admin_return import AdminReturn
class BaseAdminService:
def __init__(self, admin_return: AdminReturn) -> None:
self.admin_return = admin_return
@property
def admin_id(self) -> int:
admin_id = current_admin_id.get()
if admin_id <= 0:
raise ErrException("账户不存在")
return admin_id

View File

@@ -0,0 +1 @@
"""Admin login services."""

View File

@@ -0,0 +1,56 @@
import asyncio
from fastapi import Request
from app.common.repository.admin_user_repository import AdminUserRepository
from app.constants.model.admin_user.admin_user_status_code import AdminUserStatusCode
from app.exception.err_exception import ErrException
from app.lib.response.admin_return import AdminReturn
from app.request.admin.login_request import LoginRequest
from app.service.admin.base_admin_service import BaseAdminService
from app.service.base_token_service import BaseTokenService
class LoginService(BaseAdminService):
def __init__(
self,
user_repository: AdminUserRepository,
token_service: BaseTokenService,
admin_return: AdminReturn,
) -> None:
super().__init__(admin_return)
self.user_repository = user_repository
self.token_service = token_service
async def handle(self, payload: LoginRequest, request: Request) -> dict:
admin_info = await self.user_repository.find_by_username(payload.username)
if admin_info is None:
raise ErrException("后台管理员不存在")
password_valid = await asyncio.to_thread(
admin_info.verify_password,
payload.password,
)
if not password_valid:
raise ErrException("密码错误")
if admin_info.status == AdminUserStatusCode.DISABLE:
raise ErrException("用户已禁用")
await self.user_repository.record_login(admin_info.id, self._client_ip(request))
jwt = self.token_service.get_jwt("admin")
return self.admin_return.success(
"success",
{
"access_token": jwt.builder_access_token(str(admin_info.id)),
"refresh_token": jwt.builder_refresh_token(str(admin_info.id)),
"expire_at": int(jwt.get_config("ttl", 0)),
},
)
@staticmethod
def _client_ip(request: Request) -> str:
forwarded = request.headers.get("x-forwarded-for")
if forwarded:
return forwarded.split(",", 1)[0].strip()
return request.client.host if request.client else ""

View File

@@ -0,0 +1,22 @@
from app.lib.jwt.token import JwtToken
from app.lib.response.admin_return import AdminReturn
from app.service.admin.base_admin_service import BaseAdminService
from app.service.base_token_service import BaseTokenService
class RefreshService(BaseAdminService):
def __init__(self, token_service: BaseTokenService, admin_return: AdminReturn) -> None:
super().__init__(admin_return)
self.token_service = token_service
async def handle(self, token: JwtToken) -> dict:
return self.admin_return.success("success", await self.refresh_token(token))
async def refresh_token(self, token: JwtToken) -> dict[str, int | str]:
jwt = self.token_service.get_jwt("admin")
await jwt.add_blacklist(token)
return {
"access_token": jwt.builder_access_token(token.jwt_id),
"refresh_token": jwt.builder_refresh_token(token.jwt_id),
"expire_at": int(jwt.get_config("ttl", 0)),
}

View File

@@ -0,0 +1 @@
"""Admin profile services."""

View File

@@ -0,0 +1,20 @@
from app.common.repository.admin_user_repository import AdminUserRepository
from app.exception.err_exception import ErrException
from app.lib.response.admin_return import AdminReturn
from app.service.admin.base_admin_service import BaseAdminService
class CurrentUserService(BaseAdminService):
def __init__(
self,
user_repository: AdminUserRepository,
admin_return: AdminReturn,
) -> None:
super().__init__(admin_return)
self.user_repository = user_repository
async def handle(self) -> dict:
admin_user = await self.user_repository.find_by_id(self.admin_id)
if admin_user is None:
raise ErrException("账户不存在")
return self.admin_return.success("success", admin_user.to_public_dict())