unis_manager/app/routers/auth.py

73 lines
2.9 KiB
Python

"""登录 / 退出 / 当前用户 / 用户自己的设置(昵称、密码)。"""
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, Request, Response
from sqlalchemy.orm import Session
from .. import config, security
from ..db import get_db
from ..models import User
from ..schemas import LoginIn, PasswordIn, ProfileIn
router = APIRouter()
@router.post("/auth/login")
def login(body: LoginIn, response: Response, db: Session = Depends(get_db)):
user = db.query(User).filter(User.username == (body.username or "").strip()).one_or_none()
if user is None or not security.verify_password(body.password or "", user.password_hash, user.password_salt):
raise HTTPException(status_code=401, detail="用户名或密码不正确")
if not user.active:
raise HTTPException(status_code=403, detail="该账号已被停用,请联系管理员")
token = security.start_session(db, user)
response.set_cookie(
security.SESSION_COOKIE, token,
max_age=config.SESSION_DAYS * 86400,
httponly=True, samesite="lax", path="/",
)
return user.to_dict()
@router.post("/auth/logout")
def logout(request: Request, response: Response, db: Session = Depends(get_db)):
token = request.cookies.get(security.SESSION_COOKIE)
if token:
db.query(security.UserSession).filter(security.UserSession.token == token).delete()
db.commit()
response.delete_cookie(security.SESSION_COOKIE, path="/")
return {"ok": True}
@router.get("/auth/me")
def me(user: User = Depends(security.current_user)):
return user.to_dict()
@router.put("/auth/me")
def update_me(body: ProfileIn, user: User = Depends(security.current_user), db: Session = Depends(get_db)):
name = (body.name or "").strip()
if not name:
raise HTTPException(status_code=400, detail="昵称不能为空")
user.name = name[:64]
db.commit()
return user.to_dict()
@router.post("/auth/password")
def change_password(body: PasswordIn, request: Request, response: Response,
user: User = Depends(security.current_user), db: Session = Depends(get_db)):
if not security.verify_password(body.old_password or "", user.password_hash, user.password_salt):
raise HTTPException(status_code=400, detail="原密码不正确")
new = (body.new_password or "").strip()
if len(new) < 6:
raise HTTPException(status_code=400, detail="新密码至少 6 位")
user.password_hash, user.password_salt = security.hash_password(new)
# 改密后其余设备全部下线,只保留当前这次登录
keep = request.cookies.get(security.SESSION_COOKIE)
query = db.query(security.UserSession).filter(security.UserSession.user_id == user.id)
if keep:
query = query.filter(security.UserSession.token != keep)
query.delete(synchronize_session=False)
db.commit()
return {"ok": True}