FastAPI 不会将 cookie 返回到 React 前端

jab*_*934 5 javascript python reactjs axios fastapi

为什么 FastAPI 不将 cookie 返回到我的前端(这是一个 React 应用程序)?

这是我的代码:

@router.post("/login")
def user_login(response: Response,username :str = Form(),password :str = Form(),db: Session = Depends(get_db)):
    user = db.query(models.User).filter(models.User.mobile_number==username).first()
    if not user:
        raise HTTPException(400, detail='wrong phone number or password')
    if not verify_password(password, user.password):
        raise HTTPException(400, detail='wrong phone number or password')
    
   
    access_token = create_access_token(data={"sub": user.mobile_number})
    response.set_cookie(key="fakesession", value="fake-cookie-session-value") #here I am set cookie 
    return {"status":"success"}  
Run Code Online (Sandbox Code Playgroud)

当我从 Swagger UI autodocs 登录时,我可以使用 Chrome 浏览器上的 DevTools 在响应标头中看到 cookie。但是,当我从 React 应用程序登录时,没有返回 cookie。我正在使用 axios 发送这样的请求:

await axios.post(login_url, formdata)

Chr*_*ris 12

首先,创建 cookie,如下例所示,并确保执行 Axios POST 请求时没有返回错误,并且您收到\'status\': \'success\'带有200状态代码的响应。您可能想看看这个答案,它也解释了如何使用max_ageexpires标志。

\n
from fastapi import FastAPI, Response\n\napp = FastAPI()\n\n@app.get(\'/\')\ndef main(response: Response):\n    response.set_cookie(key=\'token\', value=\'some-token-value\', httponly=True) \n    return {\'status\': \'success\'}\n
Run Code Online (Sandbox Code Playgroud)\n

其次,正如您提到的,您在前端\xe2\x80\x94中使用React,它需要侦听与FastAPI后端使用的端口不同的端口,这意味着您正在执行CORS请求\xe2\x80\x94您需要将该withCredentials属性设置为true(默认情况下设置为false),以允许从其他来源接收/发送凭据,例如cookieHTTP 身份验证标头。两台服务器具有相同的域和协议,但端口不同,例如,http://localhost:8000http://localhost:3000认为是不同的来源(请参阅CORS 上的 FastAPI 文档此答案,它提供了有关 cookie 的一般详细信息,以及设置跨域 cookie\xe2\ 的解决方案x80\x94 在你的情况下实际上并不需要,因为后端和前端的域是相同的,因此,照常设置 cookie 就可以了。

\n

请注意http://localhost:3000,如果您通过在浏览器地址栏中输入来访问 React 前端,那么您对 ​​FastAPI 后端的 Axios 请求使用localhostURL 中的域,例如axios.post(\'http://localhost:8000\',...not axios.post(\'http://127.0.0.1:8000\',...,因为localhost127.0.0.1是两个不同的域,因此,否则,该 cookie 将无法为该域创建localhost,因为它将为127.0.0.1,即在 中使用的域创建axios创建的(然后,这将是跨域 cookie 的情况,如上面链接的答案中所述,对于您的情况,这也是不需要的)。

\n

因此,要接受服务器发送的cookie,您需要withCredentials: true在axios请求中使用;withCredentials否则,响应中的 cookie 将被忽略(当设置为时,这是默认行为false;因此,可以防止不同的域为自己的域设置 cookie)。相同withCredentials: true如果您希望将 cookie 发送到服务器,则必须在对 API 的每个后续请求中包含相同的属性,以便可以对用户进行身份验证并提供对受保护路由的访问权限

\n

因此,包含凭据的 Axios 请求应如下所示:

\n
await axios.post(url, data, {withCredentials: true}))\n
Run Code Online (Sandbox Code Playgroud)\n

请求中的等效项fetch()(即使用Fetch API)是credentials: \'include\'credentials的默认值为same-origin。使用credentials: \'include\'将导致浏览器在同源和跨源请求中包含凭据,并设置在跨源响应中发回的任何 cookie。例如:

\n
fetch(\'https://example.com\', {\n  credentials: \'include\'\n});\n
Run Code Online (Sandbox Code Playgroud)\n

重要的提示

\n

由于您正在执行跨源请求,因此要使上述任一方法正常工作,您需要显式指定允许的来源,如本答案中所述(在幕后,即设置Access-Control-Allow-Origin响应标头)。例如:

\n
origins = [\'http://localhost:3000\', \'http://127.0.0.1:3000\',\n           \'https://localhost:3000\', \'https://127.0.0.1:3000\'] \n
Run Code Online (Sandbox Code Playgroud)\n

相反,使用通配符*意味着允许所有来源;但是,这也只允许某些类型的通信,不包括涉及 的所有内容credentials,例如cookie授权标头等\xe2\x80\x94,因此,您不应使用通配符*

\n

另外,请确保allow_credentials=True在使用CORSMiddleware( 将Access-Control-Allow-Credentials响应标头设置为true)。

\n

示例(参见此处):

\n
app.add_middleware(\n    CORSMiddleware,\n    allow_origins=origins,\n    allow_credentials=True,\n    allow_methods=["*"],\n    allow_headers=["*"],\n)\n
Run Code Online (Sandbox Code Playgroud)\n