347 lines
10 KiB
Python
347 lines
10 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
|
from fastapi.security import OAuth2PasswordRequestForm
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.orm import Session
|
|
from datetime import datetime
|
|
|
|
from server.db_manager import db_manager
|
|
from server.models.user_model import User, OperationLog
|
|
from server.utils.auth_utils import AuthUtils
|
|
from server.utils.auth_middleware import get_db, get_current_user, get_admin_user, get_superadmin_user, oauth2_scheme
|
|
|
|
# 创建路由器
|
|
auth = APIRouter(prefix="/auth", tags=["auth"])
|
|
|
|
# 请求和响应模型
|
|
class Token(BaseModel):
|
|
access_token: str
|
|
token_type: str
|
|
user_id: int
|
|
username: str
|
|
role: str
|
|
|
|
class UserCreate(BaseModel):
|
|
username: str
|
|
password: str
|
|
role: str = "user"
|
|
|
|
class UserUpdate(BaseModel):
|
|
username: str | None = None
|
|
password: str | None = None
|
|
role: str | None = None
|
|
|
|
class UserResponse(BaseModel):
|
|
id: int
|
|
username: str
|
|
role: str
|
|
created_at: str
|
|
last_login: str | None = None
|
|
|
|
class InitializeAdmin(BaseModel):
|
|
username: str
|
|
password: str
|
|
|
|
# 记录操作日志
|
|
def log_operation(db: Session, user_id: int, operation: str, details: str = None, request: Request = None):
|
|
ip_address = None
|
|
if request:
|
|
ip_address = request.client.host if request.client else None
|
|
|
|
log = OperationLog(
|
|
user_id=user_id,
|
|
operation=operation,
|
|
details=details,
|
|
ip_address=ip_address
|
|
)
|
|
db.add(log)
|
|
db.commit()
|
|
|
|
# 路由:登录获取令牌
|
|
@auth.post("/token", response_model=Token)
|
|
async def login_for_access_token(
|
|
form_data: OAuth2PasswordRequestForm = Depends(),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# 查找用户
|
|
user = db.query(User).filter(User.username == form_data.username).first()
|
|
|
|
# 验证用户存在且密码正确
|
|
if not user or not AuthUtils.verify_password(user.password_hash, form_data.password):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="用户名或密码错误",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
# 更新最后登录时间
|
|
user.last_login = datetime.now()
|
|
db.commit()
|
|
|
|
# 生成访问令牌
|
|
token_data = {"sub": str(user.id)}
|
|
access_token = AuthUtils.create_access_token(token_data)
|
|
|
|
# 记录登录操作
|
|
log_operation(db, user.id, "登录")
|
|
|
|
return {
|
|
"access_token": access_token,
|
|
"token_type": "bearer",
|
|
"user_id": user.id,
|
|
"username": user.username,
|
|
"role": user.role
|
|
}
|
|
|
|
# 路由:校验是否需要初始化管理员
|
|
@auth.get("/check-first-run")
|
|
async def check_first_run():
|
|
is_first_run = db_manager.check_first_run()
|
|
return {"first_run": is_first_run}
|
|
|
|
# 路由:初始化管理员账户
|
|
@auth.post("/initialize", response_model=Token)
|
|
async def initialize_admin(
|
|
admin_data: InitializeAdmin,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# 检查是否是首次运行
|
|
if not db_manager.check_first_run():
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="系统已经初始化,无法再次创建初始管理员",
|
|
)
|
|
|
|
# 创建管理员账户
|
|
hashed_password = AuthUtils.hash_password(admin_data.password)
|
|
|
|
new_admin = User(
|
|
username=admin_data.username,
|
|
password_hash=hashed_password,
|
|
role="superadmin",
|
|
last_login=datetime.now()
|
|
)
|
|
|
|
db.add(new_admin)
|
|
db.commit()
|
|
db.refresh(new_admin)
|
|
|
|
# 生成访问令牌
|
|
token_data = {"sub": str(new_admin.id)}
|
|
access_token = AuthUtils.create_access_token(token_data)
|
|
|
|
# 记录操作
|
|
log_operation(db, new_admin.id, "系统初始化", "创建超级管理员账户")
|
|
|
|
return {
|
|
"access_token": access_token,
|
|
"token_type": "bearer",
|
|
"user_id": new_admin.id,
|
|
"username": new_admin.username,
|
|
"role": new_admin.role
|
|
}
|
|
|
|
# 路由:获取当前用户信息
|
|
@auth.get("/me", response_model=UserResponse)
|
|
async def read_users_me(current_user: User = Depends(get_current_user)):
|
|
return current_user.to_dict()
|
|
|
|
# 路由:创建新用户(管理员权限)
|
|
@auth.post("/users", response_model=UserResponse)
|
|
async def create_user(
|
|
user_data: UserCreate,
|
|
request: Request,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
# 检查用户名是否已存在
|
|
existing_user = db.query(User).filter(User.username == user_data.username).first()
|
|
if existing_user:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="用户名已存在",
|
|
)
|
|
|
|
# 创建新用户
|
|
hashed_password = AuthUtils.hash_password(user_data.password)
|
|
|
|
# 检查角色权限
|
|
# 超级管理员可以创建任何类型的用户
|
|
if user_data.role == "superadmin" and current_user.role != "superadmin":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="只有超级管理员才能创建超级管理员账户",
|
|
)
|
|
|
|
# 管理员只能创建普通用户
|
|
if current_user.role == "admin" and user_data.role != "user":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="管理员只能创建普通用户账户",
|
|
)
|
|
|
|
new_user = User(
|
|
username=user_data.username,
|
|
password_hash=hashed_password,
|
|
role=user_data.role
|
|
)
|
|
|
|
db.add(new_user)
|
|
db.commit()
|
|
db.refresh(new_user)
|
|
|
|
# 记录操作
|
|
log_operation(
|
|
db,
|
|
current_user.id,
|
|
"创建用户",
|
|
f"创建用户: {user_data.username}, 角色: {user_data.role}",
|
|
request
|
|
)
|
|
|
|
return new_user.to_dict()
|
|
|
|
# 路由:获取所有用户(管理员权限)
|
|
@auth.get("/users", response_model=list[UserResponse])
|
|
async def read_users(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
users = db.query(User).offset(skip).limit(limit).all()
|
|
return [user.to_dict() for user in users]
|
|
|
|
# 路由:获取特定用户信息(管理员权限)
|
|
@auth.get("/users/{user_id}", response_model=UserResponse)
|
|
async def read_user(
|
|
user_id: int,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="用户不存在",
|
|
)
|
|
return user.to_dict()
|
|
|
|
# 路由:更新用户信息(管理员权限)
|
|
@auth.put("/users/{user_id}", response_model=UserResponse)
|
|
async def update_user(
|
|
user_id: int,
|
|
user_data: UserUpdate,
|
|
request: Request,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="用户不存在",
|
|
)
|
|
|
|
# 检查权限
|
|
if user.role == "superadmin" and current_user.role != "superadmin":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="只有超级管理员才能修改超级管理员账户",
|
|
)
|
|
|
|
# 超级管理员账户不能被降级(只能由其他超级管理员修改)
|
|
if user.role == "superadmin" and user_data.role and user_data.role != "superadmin" and current_user.id != user.id:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="不能降级超级管理员账户",
|
|
)
|
|
|
|
# 更新信息
|
|
update_details = []
|
|
|
|
if user_data.username is not None:
|
|
# 检查用户名是否已被其他用户使用
|
|
existing_user = db.query(User).filter(User.username == user_data.username, User.id != user_id).first()
|
|
if existing_user:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="用户名已存在",
|
|
)
|
|
user.username = user_data.username
|
|
update_details.append(f"用户名: {user_data.username}")
|
|
|
|
if user_data.password is not None:
|
|
user.password_hash = AuthUtils.hash_password(user_data.password)
|
|
update_details.append("密码已更新")
|
|
|
|
if user_data.role is not None:
|
|
user.role = user_data.role
|
|
update_details.append(f"角色: {user_data.role}")
|
|
|
|
db.commit()
|
|
|
|
# 记录操作
|
|
log_operation(
|
|
db,
|
|
current_user.id,
|
|
"更新用户",
|
|
f"更新用户ID {user_id}: {', '.join(update_details)}",
|
|
request
|
|
)
|
|
|
|
return user.to_dict()
|
|
|
|
# 路由:删除用户(管理员权限)
|
|
@auth.delete("/users/{user_id}", response_model=dict)
|
|
async def delete_user(
|
|
user_id: int,
|
|
request: Request,
|
|
current_user: User = Depends(get_admin_user),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
user = db.query(User).filter(User.id == user_id).first()
|
|
if user is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="用户不存在",
|
|
)
|
|
|
|
# 检查权限
|
|
if user.role == "superadmin":
|
|
# 只有超级管理员可以删除超级管理员
|
|
if current_user.role != "superadmin":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="只有超级管理员才能删除超级管理员账户",
|
|
)
|
|
|
|
# 检查是否是最后一个超级管理员
|
|
superadmin_count = db.query(User).filter(User.role == "superadmin").count()
|
|
if superadmin_count <= 1:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="不能删除最后一个超级管理员账户",
|
|
)
|
|
|
|
# 不能删除自己的账户
|
|
if user.id == current_user.id:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="不能删除自己的账户",
|
|
)
|
|
|
|
# 记录操作
|
|
log_operation(
|
|
db,
|
|
current_user.id,
|
|
"删除用户",
|
|
f"删除用户: {user.username}, ID: {user.id}, 角色: {user.role}",
|
|
request
|
|
)
|
|
|
|
# 删除用户
|
|
db.delete(user)
|
|
db.commit()
|
|
|
|
return {"success": True, "message": "用户已删除"}
|