首页 > 解决方案 > FastAPI:注销后删除cookie不起作用

问题描述

我尝试使用FastAPI实现基于 OAuth2 Cookie 的身份验证。在调用/auth/token端点时,它完美地设置了一个 HttpOnly cookie,如下所示:

@router.post("/auth/token", response_model=Token)
async def get_token(response: Response, form_data: OAuth2PasswordRequestForm = Depends()):
    user = await authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password")
    access_token_expires = timedelta(minutes=Config.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.email_id}, expires_delta=access_token_expires
    )
    response.set_cookie(key="access_token", value=access_token, httponly=True)
    return {"access_token": access_token, "token_type": "bearer"}

/logout同样,它应该在调用端点后立即删除该 cookie ,如下所示:

@router.get("/logout")
async def logout(request: Request, response: Response, current_user: User = Depends(get_current_active_user)):
    # Also tried following two comment lines
    # response.set_cookie(key="access_token", value="", max_age=1)
    # response.delete_cookie("access_token", domain="localhost")
    response.delete_cookie("access_token")
    return templates.TemplateResponse("login.html", {"request": request, "title": "Login", "current_user": AnonymousUser()})

问题:调用/logout端点后,它应该删除它所做的cookie,但是当我再次单击/login它时,它能够检索具有相同身份验证令牌的相同cookie,即浏览器发送相同的cookie以及请求中的身份验证令牌。

这是删除cookie后响应的调试状态。它已经从响应对象中删除了 cookie,这很好:

调试器状态响应对象

这是我尝试登录AFTER LOGOUT时请求的调试状态。它仍然能够从浏览器中检索该 cookie:

调试器状态请求对象

有关如何正确删除 cookie 以便在注销后无法再次找到它的任何帮助?

标签: python-3.xcookiesoauth-2.0fastapi

解决方案


问题在于响应/logout端点正在返回。

如下图,该行response.delete_cookies(key="access_token")能够成功删除cookie 响应对象的调试状态

在返回时创建 TemplateResponse 对象时,它会创建一个新的响应,从请求中复制相同的 cookie,并隐藏我们所做的更改(删除 cookie)。所以交换函数中的最后两行logout()可以解决问题:

@router.get("/logout")
async def logout(request: Request, response: Response, current_user: User = Depends(get_current_active_user)):
    # Also tried following two comment lines
    # response.set_cookie(key="access_token", value="", max_age=1)
    # response.delete_cookie("access_token", domain="localhost")
    response = templates.TemplateResponse("login.html", {"request": request, "title": "Login", "current_user": AnonymousUser()})
    response.delete_cookie("access_token")
    return response

推荐阅读