1.基于用户名密码认证
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from starlette import status
tokens = APIRouter()
oauth2_schema = OAuth2PasswordBearer(tokenUrl="/token")
"""
客户端会向该接口发送一个带用户名和密码的请求,得到一个token
OAuth2PasswordBearer并不会创建相应的URL路径操做,只是指明客户端用来请求Token的地址
当请求到达时,FastAPI会检测请求的Authorization头信息,或者头信息的内容不是Bearer token,它会返回401状态码(UNAUTHORIZED)
"""
# 模拟数据库数据
fake_users_db = {
"jack": {
"username": "jack",
"full_name": "Jack",
"email": "jack@qq.com",
"hashed_password": "d2h3k2n4h23bn4b23h53mbn3bm24mmn43",
"disabled": True
},
"lucy": {
"username": "lucy",
"full_name": "Lucy",
"email": "lucy@qq.com",
"hashed_password": "9d34lk2n6h23le4b23h53mbn3bm24mg2nhk",
"disabled": False
}
}
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
hashed_password: str
@tokens.post("/", summary="获取Token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user_dict = fake_users_db.get(form_data.username) # 从数据库获取用户信息
if not user_dict:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User does not exists"
)
user = UserInDB(**user_dict)
print(user.hashed_password)
hashed_password = fake_hash_password(form_data.password) # 将前端提交密码进行加密后与数据库密码比对
if hashed_password != user.hashed_password:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Incorrect username or password"
)
return {"access_token": user.username, "token_type": "bearer"}
2.基于token获取用户信息
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from starlette import status
tokens = APIRouter()
# 模拟加密函数
pwd_factory = {
"password1": "d2h3k2n4h23bn4b23h53mbn3bm24mmn43",
"password2": "9d34lk2n6h23le4b23h53mbn3bm24mg2nhk"
}
# 模拟加密
def fake_hash_password(password: str):
return pwd_factory[password]
def get_user(username: str):
"""
获取用户信息
:param username:
:return:
"""
# 测试数据token直接使用的就是用户名,所以这块直接当作用户名使用,来查找用户
# 真实情况下可能会使用混合加密,将用户名作为载体混淆在token信息中,需要解析出用户名后再查找用户
if username:
user_dict = fake_users_db[username]
return User(**user_dict)
def fake_decode_token(token):
"""从token中解析用户信息"""
user = get_user(token)
return user
async def get_current_user(token: str = Depends(oauth2_schema)):
"""依赖OAuth2认证接口"""
user = fake_decode_token(token)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"}
)
return user
async def get_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Inactive user"
)
return current_user
@tokens.get("/current_users", summary="获取当前用户")
async def read_user_info(current_user: User = Depends(get_active_user)):
"""获取活跃的用户"""
return current_user