oauth2.0 FastAPI的swagger ui中的授权按钮

ogsagwnx  于 2023-06-21  发布在  其他
关注(0)|答案(2)|浏览(249)

我真的很困惑,在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文档了,但还是看不懂这部分。

jchrr9hc

jchrr9hc1#

第一个问题:swagger后端使用您编写的代码,并生成所谓的“文档”,这不是一个生产GUI,因此该按钮仅用于帮助。
区别在于:

  • 第一个:获取用户名和密码,并将它们发送到路由进行身份验证,获取结果并将其存储在导航器存储中,以便将其与您发送到API的每个请求一起发送到标头中(这与前端工程师所做的事情相同)
  • 第二个:是一个路由,就像其他任何东西一样,它接受数据,并返回数据,在您的情况下,它接受用户名和密码,并返回一个令牌,您创建这样的路由是因为REST是无状态的,前端应该负责自定义API,并存储令牌,以便在以后每次需要访问受保护的路由时发送令牌。
y53ybaqx

y53ybaqx2#

**问题1:**创建直接或间接依赖于OAuth2 PasswordBearer的路径操作时,界面会出现Authorize按钮,如文档示例:

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
    ...
async def get_current_active_user(current_user: Annotated[User, Depends(get_current_user)]):
    ...
@app.get("/users/me")
async def read_users_me(current_user: Annotated[User, Depends(get_current_active_user)]):
    ...

“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,如文档中的示例:

if not hashed_password == user.hashed_password:
    raise HTTPException(status_code=400, detail="Incorrect username or password")

相关问题