我真的很困惑,在Fastapi下面的oauth代码中需要OAuth2 PasswordRequestForm和OAuth2 PasswordBearer。我有以下两个疑问
1.谁负责在Swagger UI中创建授权按钮?
from typing import Optional
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
import uvicorn
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "fakehashedsecret",
"disabled": False,
}
}
app = FastAPI()
def fake_hash_password(password: str):
return "fakehashed" + password
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
hashed_password: str
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def fake_decode_token(token):
# This doesn't provide any security at all
# Check the next version
user = get_user(fake_users_db, token)
return user
async def get_current_user(token: str = Depends(oauth2_scheme)):
print("token value is....%s\n" % token)
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_current_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
@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=400, detail="Incorrect username or password")
user = UserInDB(**user_dict)
hashed_password = fake_hash_password(form_data.password)
if not hashed_password == user.hashed_password:
raise HTTPException(status_code=400, detail="Incorrect username or password")
return {"access_token": user.username, "token_type": "bearer"}
@app.get("/protected_hi")
async def protected_hi(current_user: User = Depends(get_current_active_user)):
return "Hi! How are you? You are in a protected Zone."
if __name__ == "__main__":
import uvicorn
uvicorn.run('test:app', host="0.0.0.0", port=5000, reload=True)
1.当我通过点击“授权”按钮登录时,我能够访问名为“/protected_hi”的保护API,而不是“授权”按钮,如果我点击“/token”URL并填写user/pass。我无法访问受保护的API。为什么会这样?在swagger UI中,“授权”按钮和“/token”URL有什么用?我已经看过fastapi文档了,但还是看不懂这部分。
2条答案
按热度按时间jchrr9hc1#
第一个问题:swagger后端使用您编写的代码,并生成所谓的“文档”,这不是一个生产GUI,因此该按钮仅用于帮助。
区别在于:
y53ybaqx2#
**问题1:**创建直接或间接依赖于OAuth2 PasswordBearer的路径操作时,界面会出现Authorize按钮,如文档示例:
“read_users_me”路径操作导致授权按钮出现,因为它依赖于“get_current_active_user”,“get_current_user”依赖于“get_current_user”,“get_current_user”依赖于“OAuth2 PasswordBearer”的名为“oauth2_scheme”的示例。
UI知道这一点,因为它正在阅读您的API的文档文件(“openapi.json”,位于“hostname:port/openapi.json”,如“localhost:8000/openapi.json”中),该文件是从您的代码自动生成的。如果你查看文件内部,你会看到提到“OAuth2 PasswordBearer”,如果你注解掉“read_users_me”路径操作函数和装饰器,它们就会消失。
请记住,Swagger UI只是一个开发辅助工具,用于调试目的,而不是用于真实的的生产用途。
**问题2:**当您点击Authorize按钮并使用它登录时,UI将从您的API接收回令牌,并将其存储在某个地方,并根据需要提供给需要它的端点。
如果您打开首选浏览器的开发人员工具面板,当您按下UI上的执行按钮时,您可以在网络选项卡中看到正在发出的请求,如果您查看请求头部分,您将看到一个名为“授权”的头,其值为“Bearer”,后跟令牌。
当你只是在UI中手动执行“/token”时,你会从API中取回令牌,但它不会在需要时自动存储和提供,这是两者之间的关键区别。
至于它们的使用,您可以使用“/token”来测试多次登录尝试,并使用按钮来执行一次登录并保存令牌以测试其他需要令牌的端点。
**编辑:**为了防止API接受无效凭证,返回某种错误的令牌,然后由UI存储,请确保在登录路径操作函数中对凭证进行某种验证,如果凭证无效,则在返回令牌之前引发HTTPException,如文档中的示例: