将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。 当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包), M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
2.1 KiB
Python
72 lines
2.1 KiB
Python
"""
|
||
app/services/auth_service.py — 认证 service
|
||
密码哈希校验、用户查找、响应格式化。
|
||
路由层不含业务逻辑,全在此。
|
||
"""
|
||
|
||
import logging
|
||
|
||
from passlib.context import CryptContext
|
||
from sqlalchemy.orm import Session
|
||
|
||
from app.core.response import raise_unauthorized
|
||
from app.middleware.workspace_guard import CurrentUser
|
||
from app.models.user import User
|
||
from app.models.workspace import WorkspaceMember
|
||
|
||
logger = logging.getLogger(__name__)
|
||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||
|
||
|
||
def hash_password(plain: str) -> str:
|
||
return pwd_context.hash(plain)
|
||
|
||
|
||
def verify_password(plain: str, hashed: str) -> bool:
|
||
return pwd_context.verify(plain, hashed)
|
||
|
||
|
||
def authenticate_user(
|
||
db: Session, username: str, password: str
|
||
) -> tuple[User, int, str]:
|
||
"""
|
||
验证用户名+密码,返回 (user, workspace_id, role)。
|
||
失败抛 CloverHTTPException 40101。
|
||
"""
|
||
user = db.query(User).filter(
|
||
User.username == username, User.is_active == True
|
||
).first()
|
||
if not user or not verify_password(password, user.hashed_password):
|
||
raise_unauthorized("用户名或密码错误")
|
||
|
||
# 取用户所在的第一个 workspace(手动建账号场景只有一个)
|
||
member = (
|
||
db.query(WorkspaceMember)
|
||
.filter(WorkspaceMember.user_id == user.id)
|
||
.first()
|
||
)
|
||
if not member:
|
||
raise_unauthorized("用户未加入任何 workspace,请联系管理员")
|
||
|
||
# 记录登录
|
||
try:
|
||
from app.models.user import LoginRecord
|
||
db.add(LoginRecord(user_id=user.id))
|
||
db.commit()
|
||
except Exception:
|
||
logger.warning("Failed to write login_record for user=%s", user.id)
|
||
db.rollback()
|
||
|
||
return user, member.workspace_id, member.role
|
||
|
||
|
||
def build_user_response(user: User, workspace_id: int, role: str) -> dict:
|
||
"""格式化用户响应体(契约§4 DTO)。"""
|
||
return {
|
||
"id": user.id,
|
||
"username": user.username,
|
||
"email": user.email,
|
||
"current_workspace_id": workspace_id,
|
||
"role": role,
|
||
}
|