1. 获取username和password
后台获取前台提交的username和password,可以使用FastAPI的安全实用性工具获取username和password。
OAuth2规定客户端必需将username和password字段作为表单数据发送(不可使用JSON)。而且规范了字段必须这样命名
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordRequestForm
app = FastAPI()
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
pass
OAuth2PasswordRequestForm是一个类依赖项,声明了如下的请求表单:
username
password
可选scope字段,是一个由空格分隔的字符串组成的大字符串
可选的grant_type字段
可选的client_id字段
可选的 client_secret字段
2. tokens 令牌
现在使用表单中的username从(伪)数据库中获取用户数据,如果没有这个用户就返回一个错误。若是获取到这个用户,先进行Pydantic UserInDB模型,然后进行密码密文校验。
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
# 伪数据库
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "fakehashedsecret",
"disabled": False,
},
"alice": {
"username": "alice",
"full_name": "Alice Wonderson",
"email": "alice@example.com",
"hashed_password": "fakehashedsecret2",
"disabled": True,
},
}
def fake_hash_password(password: str):
return "fakehashed" + password
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
hashed_password: str
@app.post("/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_400_BAD_REQUEST, detail="Incorrect username or password!")
user = UserInDB(**user_dict) # 进行用户模型校验
hashed_password = fake_hash_password(form_data.password) # 将表单密码进行hash加密
if not 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"}
最后返回一个JSON数据的token令牌,该JSON对象包含:
token_type 因为实例中使用了Bearer令牌,所以令牌类型为Bearer
access_token 令牌字符串
3. 获取活跃用户信息
前面已经完成了令牌的获取功能,与之前的获取当前用户的功能进行合并:
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
oauth2_schema = OAuth2PasswordBearer(tokenUrl="/token") # 执行生成token的地址
# 伪数据库
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "fakehashedsecret",
"disabled": False,
},
"alice": {
"username": "alice",
"full_name": "Alice Wonderson",
"email": "alice@example.com",
"hashed_password": "fakehashedsecret2",
"disabled": True,
},
}
def fake_hash_password(password: str):
return "fakehashed" + password
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
hashed_password: str
@app.post("/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_400_BAD_REQUEST, detail="Incorrect username or password!")
user = UserInDB(**user_dict) # 进行用户模型校验
hashed_password = fake_hash_password(form_data.password) # 将表单密码进行hash加密
if not 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"}
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def fake_decode_token(token: str):
user = get_user(fake_users_db, token)
return user
async def get_current_user(token: str = Depends(oauth2_schema)):
user = fake_decode_token(token)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authenticate credentials",
headers={"WWW-Authentiacate": "Bearer"}
)
return user
async def get_current_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
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_active_user)):
return current_user
- 在生成token的基础上进行活跃用户信息的获取:
1.1 首先需要将生成token的地址进行指向实际生成token的路径操作函数
1.2 获取活跃用户请求时就会去获取认证的token
1.3 一旦获取到token就与正常的API请求一样 - 具体的表现是在交互文档中:
2.1 先点击右上角的Authorize按钮进行认证,此时后台会生成一个JSON对象,内含access_token字段
2.2 前台获取到 这个access_token,将其存到某处
2.3 点击下面的路径操作,如获取活跃用户的API,会在请求头中携带该token进行认证,以及获取相应的用户信息