Files
nanocode/personal-blog-neobrutalism/backend/routers/auth.py
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

126 lines
3.9 KiB
Python

"""
认证路由
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from database import get_db
from models import Admin
from schemas import LoginRequest, LoginResponse, PasswordChange
router = APIRouter(prefix="/api/auth", tags=["认证"])
# 安全配置
SECRET_KEY = "your-secret-key-change-in-production" # 生产环境修改
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_DAYS = 7
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
def verify_password(plain_password, hashed_password):
"""验证密码"""
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password):
"""生成密码哈希"""
return pwd_context.hash(password)
def create_access_token(data: dict, expires_delta: timedelta = None):
"""创建JWT令牌"""
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(days=ACCESS_TOKEN_EXPIRE_DAYS)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
async def get_current_admin(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
"""获取当前登录管理员"""
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无法验证凭据",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
admin = db.query(Admin).filter(Admin.username == username).first()
if admin is None:
raise credentials_exception
return admin
@router.post("/login", response_model=LoginResponse)
def login(login_data: LoginRequest, db: Session = Depends(get_db)):
"""管理员登录"""
admin = db.query(Admin).filter(Admin.username == login_data.username).first()
if not admin or not verify_password(login_data.password, admin.password_hash):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户名或密码错误"
)
access_token = create_access_token(data={"sub": admin.username})
return {"access_token": access_token, "token_type": "bearer"}
@router.post("/change-password")
def change_password(
password_data: PasswordChange,
current_admin: Admin = Depends(get_current_admin),
db: Session = Depends(get_db)
):
"""修改密码"""
# 验证原密码
if not verify_password(password_data.old_password, current_admin.password_hash):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="原密码错误"
)
# 更新密码
current_admin.password_hash = get_password_hash(password_data.new_password)
db.commit()
return {"message": "密码修改成功"}
@router.get("/me")
def get_me(current_admin: Admin = Depends(get_current_admin)):
"""获取当前管理员信息"""
return {"username": current_admin.username}
def init_admin(db: Session):
"""初始化默认管理员账号"""
admin = db.query(Admin).filter(Admin.username == "admin").first()
if not admin:
admin = Admin(
username="admin",
password_hash=get_password_hash("admin123")
)
db.add(admin)
db.commit()
print("✅ 默认管理员账号已创建: admin / admin123")