加上登录和角色权限,并用 Vue 控制台区分用户与管理员。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"""注册、登录,以及首次启动时创建管理员。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import secrets
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.clock import utcnow
|
||||
from app.config import settings
|
||||
from app.errors import AppError
|
||||
from app.models import User, UserRole
|
||||
from app.security import hash_password, verify_password
|
||||
from app.services.registry import register_user
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def register_account(
|
||||
session: Session,
|
||||
wallet_address: str,
|
||||
username: str | None,
|
||||
password: str | None,
|
||||
) -> User:
|
||||
name = _clean_username(username)
|
||||
secret = (password or "").strip()
|
||||
if name and not secret:
|
||||
raise AppError("设置用户名时必须填写密码")
|
||||
if secret and not name:
|
||||
raise AppError("设置密码时必须填写用户名")
|
||||
if secret and len(secret) < 6:
|
||||
raise AppError("密码至少 6 位")
|
||||
return register_user(
|
||||
session,
|
||||
wallet_address,
|
||||
username=name,
|
||||
password_hash=hash_password(secret) if secret else None,
|
||||
)
|
||||
|
||||
|
||||
def authenticate(
|
||||
session: Session,
|
||||
wallet_address: str | None,
|
||||
username: str | None,
|
||||
password: str | None,
|
||||
) -> User:
|
||||
name = _clean_username(username)
|
||||
wallet = (wallet_address or "").strip()
|
||||
secret = (password or "").strip()
|
||||
if name and secret:
|
||||
user = session.scalar(select(User).where(User.username == name))
|
||||
if user is None or not verify_password(secret, user.password_hash):
|
||||
raise AppError("账号或密码错误", 401)
|
||||
return user
|
||||
if wallet and secret:
|
||||
user = session.scalar(select(User).where(User.wallet_address == wallet))
|
||||
if user is None or not verify_password(secret, user.password_hash):
|
||||
raise AppError("账号或密码错误", 401)
|
||||
return user
|
||||
if wallet:
|
||||
user = session.scalar(select(User).where(User.wallet_address == wallet))
|
||||
if user is None:
|
||||
raise AppError("钱包未注册", 401)
|
||||
if user.role == UserRole.ADMIN:
|
||||
raise AppError("管理员请使用账号密码登录", 403)
|
||||
return user
|
||||
raise AppError("请填写钱包地址,或账号和密码")
|
||||
|
||||
|
||||
def ensure_admin(session: Session) -> None:
|
||||
username = _clean_username(settings.admin_username) or "admin"
|
||||
existing = session.scalar(select(User).where(User.username == username))
|
||||
if existing is not None:
|
||||
if existing.role != UserRole.ADMIN:
|
||||
existing.role = UserRole.ADMIN
|
||||
session.flush()
|
||||
return
|
||||
generated = not settings.admin_password
|
||||
password = settings.admin_password or secrets.token_urlsafe(12)
|
||||
wallet = settings.admin_wallet.strip() or "admin-root"
|
||||
if session.scalar(select(User).where(User.wallet_address == wallet)) is not None:
|
||||
wallet = f"{wallet}-{secrets.token_hex(3)}"
|
||||
session.add(
|
||||
User(
|
||||
wallet_address=wallet,
|
||||
username=username,
|
||||
password_hash=hash_password(password),
|
||||
role=UserRole.ADMIN,
|
||||
created_at=utcnow(),
|
||||
)
|
||||
)
|
||||
session.flush()
|
||||
if generated:
|
||||
logger.warning("已创建管理员 %s,初始密码:%s", username, password)
|
||||
|
||||
|
||||
def _clean_username(username: str | None) -> str | None:
|
||||
if username is None:
|
||||
return None
|
||||
cleaned = username.strip().lower()
|
||||
return cleaned or None
|
||||
Reference in New Issue
Block a user