refactor:重构route-service-repositories,删除测试代码 #3
Generated
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
<TabSessionState>
|
<TabSessionState>
|
||||||
<option name="provider" value="claude" />
|
<option name="provider" value="claude" />
|
||||||
<option name="sessionId" value="ed440cf1-c034-44b5-b5db-bc5afb824005" />
|
<option name="sessionId" value="ed440cf1-c034-44b5-b5db-bc5afb824005" />
|
||||||
<option name="cwd" value="D:\Projects\py\Memory_demo" />
|
<option name="cwd" value="D:\Projects\py\Mutual_Fund" />
|
||||||
<option name="model" value="claude-sonnet-5[1m]" />
|
<option name="model" value="claude-sonnet-5[1m]" />
|
||||||
<option name="permissionMode" value="default" />
|
<option name="permissionMode" value="default" />
|
||||||
</TabSessionState>
|
</TabSessionState>
|
||||||
|
|||||||
+1
-2
@@ -3,8 +3,7 @@
|
|||||||
"""
|
"""
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from api.routers import auth, health
|
from api.routers import auth
|
||||||
|
|
||||||
api_router = APIRouter()
|
api_router = APIRouter()
|
||||||
api_router.include_router(health.router, prefix="/api", tags=["系统"])
|
|
||||||
api_router.include_router(auth.router, prefix="/api", tags=["认证"])
|
api_router.include_router(auth.router, prefix="/api", tags=["认证"])
|
||||||
+5
-22
@@ -1,38 +1,21 @@
|
|||||||
"""认证路由:登录签发 JWT + 当前用户信息(get_current_user 依赖注入示例)。"""
|
"""认证路由:登录 + 当前用户(业务在 service/auth.py,路由只做编排)。"""
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from api.deps import get_current_user
|
from api.deps import get_current_user
|
||||||
from config.deps import get_db
|
from config.deps import get_db
|
||||||
from schemas.auth import LoginReq
|
|
||||||
from model.sys_user import SysUser
|
from model.sys_user import SysUser
|
||||||
from repositories.sys_user import SysUserRepo
|
from schemas.auth import LoginReq
|
||||||
from service.auth import create_token, verify_password
|
from service.auth import login as auth_login
|
||||||
from utils.exceptions import ForbiddenError, ParamError
|
from service.auth import user_payload
|
||||||
from utils.response import success
|
from utils.response import success
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
def user_payload(u: SysUser) -> dict:
|
|
||||||
return {
|
|
||||||
"id": u.id,
|
|
||||||
"username": u.username,
|
|
||||||
"user_type": u.user_type,
|
|
||||||
"employee_role": u.employee_role,
|
|
||||||
"customer_level": u.customer_level,
|
|
||||||
"status": u.status,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/auth/login")
|
@router.post("/auth/login")
|
||||||
async def login(body: LoginReq, db: AsyncSession = Depends(get_db)):
|
async def login(body: LoginReq, db: AsyncSession = Depends(get_db)):
|
||||||
user = await SysUserRepo(db).get_by_username(body.username)
|
return success(await auth_login(db, body.username, body.password))
|
||||||
if user is None or not verify_password(body.password, user.password_hash):
|
|
||||||
raise ParamError("用户名或密码错误")
|
|
||||||
if user.status != "正常":
|
|
||||||
raise ForbiddenError("账号状态异常,无法登录")
|
|
||||||
return success({"token": create_token(user.id), "user": user_payload(user)})
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/auth/me")
|
@router.get("/auth/me")
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
"""系统健康检查:四库就绪状态 + 各库探测耗时(任一失败返回 503 + 明细)。"""
|
|
||||||
from fastapi import APIRouter
|
|
||||||
from fastapi.responses import JSONResponse
|
|
||||||
|
|
||||||
from config.database import check_ready_detail
|
|
||||||
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/health/ready")
|
|
||||||
async def health_ready():
|
|
||||||
dbs = await check_ready_detail()
|
|
||||||
all_ok = all(v["status"] == "ok" for v in dbs.values())
|
|
||||||
return JSONResponse(
|
|
||||||
status_code=200 if all_ok else 503,
|
|
||||||
content={"status": "ready" if all_ok else "degraded", "dbs": dbs},
|
|
||||||
)
|
|
||||||
+29
-2
@@ -1,4 +1,4 @@
|
|||||||
"""认证服务:JWT 签发/校验(HS256)+ 密码哈希/校验。
|
"""认证服务:登录业务 + JWT 签发/校验(HS256)+ 密码哈希/校验。
|
||||||
|
|
||||||
密码用 stdlib PBKDF2(免 bcrypt 依赖),存储格式自描述:
|
密码用 stdlib PBKDF2(免 bcrypt 依赖),存储格式自描述:
|
||||||
pbkdf2_sha256$600000$<salt_hex>$<digest_hex>
|
pbkdf2_sha256$600000$<salt_hex>$<digest_hex>
|
||||||
@@ -9,8 +9,12 @@ import secrets
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from config.settings import settings
|
from config.settings import settings
|
||||||
|
from model.sys_user import SysUser
|
||||||
|
from repositories.sys_user import SysUserRepo
|
||||||
|
from utils.exceptions import ForbiddenError, ParamError
|
||||||
|
|
||||||
_ITERATIONS = 600_000
|
_ITERATIONS = 600_000
|
||||||
|
|
||||||
@@ -43,4 +47,27 @@ def verify_password(password: str, stored: str) -> bool:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
calc = hashlib.pbkdf2_hmac("sha256", password.encode(), bytes.fromhex(salt), int(iters))
|
calc = hashlib.pbkdf2_hmac("sha256", password.encode(), bytes.fromhex(salt), int(iters))
|
||||||
return hmac.compare_digest(calc.hex(), digest)
|
return hmac.compare_digest(calc.hex(), digest)
|
||||||
|
|
||||||
|
|
||||||
|
# ---- 登录业务(路由层只编排,不碰数据/逻辑) ----
|
||||||
|
def user_payload(u: SysUser) -> dict:
|
||||||
|
"""对外暴露的用户信息(不含密码等敏感字段)。"""
|
||||||
|
return {
|
||||||
|
"id": u.id,
|
||||||
|
"username": u.username,
|
||||||
|
"user_type": u.user_type,
|
||||||
|
"employee_role": u.employee_role,
|
||||||
|
"customer_level": u.customer_level,
|
||||||
|
"status": u.status,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def login(db: AsyncSession, username: str, password: str) -> dict:
|
||||||
|
"""校验账号密码与状态,成功签发 token 并返回用户信息;失败抛业务异常。"""
|
||||||
|
user = await SysUserRepo(db).get_by_username(username)
|
||||||
|
if user is None or not verify_password(password, user.password_hash):
|
||||||
|
raise ParamError("用户名或密码错误")
|
||||||
|
if user.status != "正常":
|
||||||
|
raise ForbiddenError("账号状态异常,无法登录")
|
||||||
|
return {"token": create_token(user.id), "user": user_payload(user)}
|
||||||
Reference in New Issue
Block a user