“AttributeError: ‘property’ object has no attribute ‘get'”在使用FastAPI中使用Depends时发生

huangapple go评论62阅读模式
英文:

"AttributeError: 'property' object has no attribute 'get'" when using Depends in FastAPI

问题

为了在FastAPI端点中实现身份验证,我想要利用FastAPI最新版本(>=0.95)提供的Depends功能。我已经尝试了几种实现方式,但遇到了一个错误:“AttributeError: 'property' object has no attribute 'get'”。这意味着在使用Depends时,Starlette的Request对象未被识别为这样的对象。

端点实现:

@app.get("/")
async def home(user: Annotated[User, Depends(authenticate_request(Request))]):
    """
    status _summary_
    Returns status message if service is running
    """
    if isinstance(user, User):
        return {"Welcome, service is running ok!"}
    raise HTTPException(
        status_code=401,
        detail="User not authorized!",
    )

authenticate_request 函数检查基于提供的 Request 的 cookie 的有效性:

def authenticate_request(request: Request) -> User:
    cookie1 = request.cookies.get("x")
    cookie2 = request.cookies.get("y")
    if cookie1 is not None and cookie2 is not None:
        tenant = get_tenant(request)
        if user := authenticate_cookies(cookie1, cookie2, tenant):
            if not tenant.startswith(user.tenant):
                print("Unauthorized: Token hostname mismatch")
                raise Exception("Token hostname mismatch")
            return user
    print("Unauthorized: please login")
    raise HTTPException(status_code=401, detail="Unauthorized: please login")

这导致错误:“AttributeError: 'property' object has no attribute 'get'”。这意味着 Request 对象未正确传递或未被正确识别。

然后,我尝试解决这个问题,而不使用 Depends

@app.get("/")
async def home(request: Request):
    """
    status _summary_
    Returns status message if service is running
    """
    user = authenticate_request(request=request)
    if isinstance(user, User):
        return {"Welcome, service is running ok!"}
    raise HTTPException(
        status_code=401,
        detail="User not authorized!",
    )

这个方法是正常工作的。如果没有提供有效的 cookie,就会返回 401 错误。基于这一点,我得出结论,我的 authenticate_request() 函数是正常工作的。

有人知道为什么在 Depends() 和另一种解决方案之间存在行为差异吗?

非常感谢帮助!

致敬,
Laurens

英文:

To implement authentication for a FastAPI endpoint, I want to make use of the Depends functionality offered in the latest versions (>=0.95) of FastAPI. I have tried several ways to implement it but I am facing an error "AttributeError: 'property' object has no attribute 'get'". This implies that the starlette Request object is not recognised as such when using Depends.

Endpoint implementation:

@app.get("/")
async def home(user: Annotated[User, Depends(authenticate_request(Request))]):
    """
    status _summary_
    Returns status message if service is running
    """
    if isinstance(user, User):
        return {"Welcome, service is running ok!"}
    raise HTTPException(
        status_code=401,
        detail="User not authorized!",
    )

Function authenticate_request checks validity of cookies based on provided Request:

def authenticate_request(request: Request) -> User:
    cookie1 = request.cookies.get("x")
    cookie2 = request.cookies.get("y")
    if cookie1 is not None and cookie2 is not None:
        tenant = get_tenant(request)
        if user := authenticate_cookies(cookie1, cookie2, tenant):
            if not tenant.startswith(user.tenant):
                print("Unauthorized: Token hostname mismatch")
                raise Exception("Token hostname mismatch")
            return user
    print("Unauthorized: please login")
    raise HTTPException(status_code=401, detail="Unauthorized: please login")

This results in error "AttributeError: 'property' object has no attribute 'get'". This implies that the Request object is not passed correctly or is not recognised as such.

I then tried to solve this without using Depends:

@app.get("/")
async def home(request: Request):
    """
    status _summary_
    Returns status message if service is running
    """
    user = authenticate_request(request=request)
    if isinstance(user, User):
        return {"Welcome, service is running ok!"}
    raise HTTPException(
        status_code=401,
        detail="User not authorized!",
    )

This is working correctly. If no valid cookie is provided a 401 is returned. Based on this I come to the conclusion that my authenticate_request() function is working correctly.

Does anybody know why there is a difference in behaviour between Depends() and the alternative solution?

Help is much appreciated!

Regards,
Laurens

答案1

得分: 1

当使用 Depends() 时,您只需在括号内传递依赖函数的名称。如 文档 中所述:

> 首先,让我们专注于依赖项
>
> 它只是一个函数,可以接受与路径操作函数相同的所有参数
>
> 它具有与所有路径操作函数相同的形状和结构。
>
> 您可以将其视为一个没有“装饰器”的路径操作函数(没有 @app.get("/some-path"))。
>
> 它可以返回您想要的任何内容。

因此,您的依赖函数需要使用的任何其他参数,您只需在该函数中声明它们,而不是通过 Depends() 传递它们。同样适用于 Request 对象。

因此,您的路径操作函数(也称为端点)应如下所示:

@app.get("/")
async def home(user: Annotated[User, Depends(authenticate_request)]):
    pass

您的 authenticate_request 依赖函数应如下所示:

def authenticate_request(request: Request) -> User:
    pass
英文:

When using Depends(), you just need to pass the name of the dependency function within the brackets. As described in the documentation:

> Let's first focus on the dependency.
>
> It is just a function that can take all the same parameters that a
> path operation function can take.
>
> And it has the same shape and structure that all your path operation
> functions
have.
>
> You can think of it as a path operation function without the
> "decorator" (without the @app.get("/some-path")).
>
> And it can return anything you want.

Thus, any other parameters that your dependency function takes, you simply need to declare them in that function and not passing them through Depends(). Same applies to the Request object.

Hence, your path operation function (also known as endpoint) should look like this:

@app.get("/")
async def home(user: Annotated[User, Depends(authenticate_request)]):
    pass

and your authenticate_request dependency function should be as follows:

def authenticate_request(request: Request) -> User:
    pass

huangapple
  • 本文由 发表于 2023年6月12日 16:34:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76454850.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定