以Depends的方式定义jwt

from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi.security import OAuth2PasswordBearer
from fastapi import Depends, HTTPException, status
from db import Curd
from typing import Optional
from datetime import datetime
from config import settings
from utils import logger
from .db import get_db
from datetime import timedelta


pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_schema = OAuth2PasswordBearer(tokenUrl="/users/login")


def hash_password(plain_password: str) -> str:
    return pwd_context.hash(plain_password)


def verity_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)


async def jwt_authenticate_user(username: str, password: str):
    db = get_db()
    user = await Curd.get_user_by_name(await db.__anext__(), username)
    if not user:
        return False
    if not verity_password(password, user.password):
        return False
    return user


def created_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=settings.config.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(claims=to_encode, key=settings.default.SECRET_KEY, algorithm="HS256")
    return encoded_jwt


async def jwt_verity(token: str = Depends(oauth2_schema)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        playload = jwt.decode(token=token, key=settings.default.SECRET_KEY, algorithms=["HS256"])
    except JWTError as e:
        logger.error("验证出现错误:\n", e)
        raise credentials_exception
    else:
        return playload


async def jwt_get_current_user(playload: dict = Depends(jwt_verity)):
    db = get_db()
    user_id = int(playload.get("sub"))
    user = await Curd.get_user_by_id(await db.__anext__(), user_id=user_id)
    return user


async def jwt_verity_admin(playload: dict = Depends(jwt_verity)):
    db = get_db()
    user_id = int(playload.get("sub"))
    is_admin = playload.get("is_admin")
    if is_admin:
        user = await Curd.get_user_by_id(await db.__anext__(), user_id=user_id)
        if user.is_admin:
            return
    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )

需要分发token的url

router = APIRouter(
    prefix="/users",
    tags=["user"],
)

# it defind at dependencies.jwt
# oauth2_schema = OAuth2PasswordBearer(tokenUrl="/users/token")


@router.post("/register", response_model=UserToken)
async def user_register(user: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db)):
    if await Curd.is_user_name_exists(db, user.username):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail="username already exists")
    hashed_password = hash_password(user.password)
    new_user = UserCreate(id=worker.get_id(), name=user.username, password=hashed_password)
    await Curd.register_user(db, new_user)


@router.post("/login", response_model=UserToken)
async def user_login(user: OAuth2PasswordRequestForm = Depends()):
    user = await jwt_authenticate_user(username=user.username, password=user.password)
    if not user:
        raise HTTPException(
            status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token = created_access_token(data={"sub": str(user.id)})
    user_token = UserToken(username=user.name,
                           access_token=access_token,
                           token_type="bearer")
    return user_token

需要token进行访问限制的url

router = APIRouter(
    prefix="/works",
    tags=["works"],
)


@router.get("/get", response_model=Works)
async def test(
        order: int,
        nsfw: bool,
        page: int,
        sort: int,
        user: User = Depends(jwt_get_current_user),
        db: AsyncSession = Depends(get_db),
        ):
    works = await Curd.get_works(db, user.id, order, nsfw, page, sort)
    return works