代码提交
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
"""认证业务:登录、建号、改密。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.exceptions import AuthError, BusinessError, ConflictError
|
||||
from app.core.security import create_access_token, hash_password, verify_password
|
||||
from app.dao.account_dao import AccountDao
|
||||
from app.model import Account, Role
|
||||
from app.schema.auth_schema import AccountCreate, PasswordChange
|
||||
|
||||
|
||||
class AuthService:
|
||||
@classmethod
|
||||
def login(cls, db: Session, username: str, password: str) -> tuple[Account, str, int]:
|
||||
account = AccountDao.get_by_username(db, username)
|
||||
if account is None or not verify_password(password, account.hashed_password):
|
||||
# 不区分"用户不存在"和"密码错误",避免账号枚举
|
||||
raise AuthError("用户名或密码不正确")
|
||||
if not account.is_active:
|
||||
raise AuthError("该账号已被停用,请联系管理员")
|
||||
|
||||
account.last_login_at = datetime.now()
|
||||
db.flush()
|
||||
|
||||
expires_seconds = settings.JWT_EXPIRE_MINUTES * 60
|
||||
token = create_access_token(
|
||||
{"sub": str(account.id), "username": account.username, "role": account.role}
|
||||
)
|
||||
return account, token, expires_seconds
|
||||
|
||||
@classmethod
|
||||
def create_account(cls, db: Session, payload: AccountCreate) -> Account:
|
||||
if AccountDao.get_by_username(db, payload.username, with_deleted=True):
|
||||
raise ConflictError(f"登录名「{payload.username}」已被占用")
|
||||
if payload.role not in {r.value for r in Role}:
|
||||
raise BusinessError(f"角色只能是 {'/'.join(r.value for r in Role)}")
|
||||
|
||||
account = Account(
|
||||
username=payload.username,
|
||||
hashed_password=hash_password(payload.password),
|
||||
real_name=payload.real_name,
|
||||
role=payload.role,
|
||||
advisor_id=payload.advisor_id,
|
||||
)
|
||||
db.add(account)
|
||||
db.flush()
|
||||
return account
|
||||
|
||||
@classmethod
|
||||
def change_password(cls, db: Session, account: Account, payload: PasswordChange) -> None:
|
||||
if not verify_password(payload.old_password, account.hashed_password):
|
||||
raise BusinessError("原密码不正确")
|
||||
if payload.old_password == payload.new_password:
|
||||
raise BusinessError("新密码不能与原密码相同")
|
||||
account.hashed_password = hash_password(payload.new_password)
|
||||
db.flush()
|
||||
Reference in New Issue
Block a user