FastAPI不会返回Cookie以响应前端

r3i60tvu  于 2022-10-21  发布在  iOS
关注(0)|答案(1)|浏览(248)

为什么FastAPI不把Cookie返回给我的前端,这是一款Reaction应用程序?
以下是我的代码:

@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"}

当我从Swagger UI Autodocs登录时,我可以在Chrome浏览器上使用DevTool在响应头中看到Cookie。然而,当我从我的Reaction应用程序登录时,没有返回任何cookie。我使用AXIOS发送如下请求:
await axios.post(login_url, formdata)

d8tt03nd

d8tt03nd1#

首先,确保在执行Axios POST请求时没有返回错误,并且您得到了带有200状态代码的"status": "success"响应。
其次,正如您提到的那样,您在前端使用Reaction-需要侦听与FastAPI后端使用的端口不同的端口,这意味着您正在执行CORS请求-您需要将withCredentials属性设置为true(缺省情况下设置为false),以便允许从/向其他来源接收/发送凭据,例如cookiesHTTP authentication头。两台服务器具有相同的域和协议,但不同端口,例如http://localhost:8000http://localhost:3000,被视为不同的来源(请参阅FastAPI documentation on CORSthis answer,其中介绍了一般的Cookie,以及设置跨域Cookie的解决方案-在您的情况下,实际上并不需要跨域Cookie,因为后端和前端的域是相同的,因此,正常设置Cookie会很好)。
注意如果您是从浏览器访问您在http://localhost:3000上的React前端,那么您对FastAPI后端的Axios请求应该使用URL中的localhost域,例如axios.post('http://localhost:8000',...不是http://127.0.0.1:8000,因为localhost127.0.0.1是两个不同的域,因此,否则将无法为localhost域创建cookie,因为它将为127.0.0.1创建,即axios请求中使用的域(这将是跨域cookie的情况,如上面链接的答案所述)。
因此,要接受服务器发送的Cookie,您需要在Axios请求中使用withCredentials: true;否则,这些Cookie将在响应中被忽略(当withCredentials设置为false时,这是默认行为;因此,防止不同的域为其自己的域设置Cookie)。如果您希望将Cookie发送到服务器,以便可以对用户进行身份验证并提供对受保护路由的访问,则必须在对您的API的每个后续请求中包括相同的withCredentials: true属性。
因此,包含凭据的Axios请求应如下所示:

await axios.post(url, data, {withCredentials: true}))

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

fetch('https://example.com', {
  credentials: 'include'
});

注意事项

要使上述两种方法之一发挥作用,您需要显式指定允许的来源,如this answer中所述(即在幕后设置Access-Control-Allow-Origin响应头)。例如:

origins = ['http://localhost:3000', 'http://127.0.0.1:3000',
           'https://localhost:3000', 'https://127.0.0.1:3000']

使用"*"通配符将只允许某些类型的通信,排除涉及credentials的所有内容,如cookie授权头部等。
此外,在使用CORSMiddleware(将Access-Control-Allow-Credentials响应头设置为true)时,请确保设置allow_credentials=True

相关问题