fastapi security oauth2-jwt 加注释代码

from datetime import datetime, timedelta
from typing import Optional


from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel


# to generate a string like this run:
# openssl rand -hex 32
SECRET_KEY = "766dadc27acd4c9b603adb9e7d4943bd0c43bbace609fad9b3bb5a4d1dc08d00H"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30


fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "full_name": "John Doe",
        "email": "johndoe@example.com",
        "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
        "disabled": False,
    }
}


class Token(BaseModel):
    access_token: str
    token_type: str


class TokenData(BaseModel):
    username: Optional[str] = None


class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None
    disabled: Optional[bool] = None


class UserInDb(User):
    hashed_password: str


pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

app = FastAPI()


# 判断明文密码和加密后的密码是否相同
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 get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return UserInDb(**user_dict) # 返回UserInDb的字典


def authenticate_user(fake_db, username: str, password: str):
    user = get_user(fake_db, username) # 返回UserInDb的字典
    if not user:
        return False
    if not verify_password(password, user.hashed_password): #比较加密后的hash值是否一致
        return False
    return user # 返回UserInDb的字典


# 创建token
def create_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=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) # 加密时只有一种加密算法
    return encoded_jwt # 返回token

# 获取当前用户 有auth验证
# oauth2_scheme 返回的是 {"access_token": access_token, "token_type": "Bearer"}
# access_token = create_access_token({"sub": user.username}, expires_delta=access_token_expires)
async def get_current_user(token: str = Depends(oauth2_scheme)):
    # 创建抛出异常提示信息
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        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
        token_data = TokenData(username=username) # TokenData只有一个username字段
    except JWTError:
        raise credentials_exception
    user = get_user(fake_users_db, username=token_data.username) # 返回UserInDb的字典
    if user is None:
        raise credentials_exception
    return user # 返回UserInDb的字典


# 返回当前活跃用户
async def get_current_active_user(current_user: User = Depends(get_current_user)):
    # 返回的是UserInDb, 经过User类过滤后, 去掉字典中的密码,仅返回User字典
    if current_user.disabled:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user # 返回User的字典, 返回的字典中没有密码


@app.post("/token", response_model=Token)
async def login_for_access_token(formdata: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, formdata.username, formdata.password) # 返回UserInDb的字典
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    # 设定token过期时间, 以分钟为单位
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    # 返回jwt加密后的token
    access_token = create_access_token({"sub": user.username}, expires_delta=access_token_expires)
    print('access_token', access_token)
    return {"access_token": access_token, "token_type": "Bearer"}


@app.get("/users/me/", response_model=User)
async def read_users_me(current_user: User = Depends(get_current_active_user)):
    return current_user # 返回User字典


@app.get("/users/me/items")
async def read_own_items(current_user: User = Depends(get_current_active_user)):
    return [{"item_id": "Foo", "owner": current_user.username}]

参考
https://fastapi.tiangolo.com/zh/tutorial/security/oauth2-jwt/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值