FastAPI no devuelve cookies a la interfaz de React
¿Por qué FastAPI no devuelve la cookie a mi interfaz, que es una aplicación React?
Aquí está mi código:
@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"}
Cuando inicio sesión desde los autodocs de Swagger UI, puedo ver la cookie en los encabezados de respuesta usando DevTools en el navegador Chrome. Sin embargo, cuando inicio sesión desde mi aplicación React, no se devuelve ninguna cookie. Estoy usando axios para enviar la solicitud de esta manera:
await axios.post(login_url, formdata)
Primero, cree la cookie, como se muestra en el ejemplo siguiente, y asegúrese de que no se devuelva ningún error al realizar la solicitud POST de Axios y de que obtenga una 'status': 'success'
respuesta con 200
el código de estado. Es posible que también desee echar un vistazo a esta respuestamax_age
, que también explica cómo usar las banderas y expires
.
from fastapi import FastAPI, Response
app = FastAPI()
@app.get('/')
def main(response: Response):
response.set_cookie(key='token', value='some-token-value', httponly=True)
return {'status': 'success'}
En segundo lugar, como mencionaste que estás usando React en el frontend, que debe estar escuchando en un puerto diferente al usado para el backend FastAPI, lo que significa que estás realizando solicitudes CORS , debes configurar la withCredentials
propiedad en true
(por defecto esto está configurado en false
), para permitir recibir/enviar credenciales, como cookies y encabezados de autenticación HTTP , desde/hacia otros orígenes. Dos servidores con el mismo dominio y protocolo, pero diferentes puertos , por ejemplo, se consideran orígenes diferentes (consulte la documentación de FastAPI en CORS y esta respuesta , que proporciona detalles sobre las cookies en general, así como soluciones para configurar cookies entre dominios, que usted en realidad no es necesario en su caso, ya que el dominio es el mismo tanto para el backend como para el frontend y, por lo tanto, configurar la cookie como de costumbre funcionaría bien).http://localhost:8000
http://localhost:3000
Tenga en cuenta que si accede a su interfaz de React escribiendo http://localhost:3000
en la barra de direcciones de su navegador, entonces sus solicitudes de Axios al backend de FastAPI deben usar el localhost
dominio en la URL, por ejemplo, axios.post('http://localhost:8000',...
y no axios.post('http://127.0.0.1:8000',...
, ya que localhost
y 127.0.0.1
son dos dominios diferentes y, por lo tanto, De lo contrario, la cookie no se crearía para el localhost
dominio, ya que se crearía para 127.0.0.1
, es decir, el dominio utilizado en la axios
solicitud (y luego, ese sería el caso de las cookies entre dominios, como se describe en la respuesta vinculada anteriormente). que nuevamente, en su caso, no sería necesario).
Por lo tanto, para aceptar las cookies enviadas por el servidor, debe utilizarlas withCredentials: true
en su solicitud de Axios; de lo contrario, las cookies se ignorarán en la respuesta (que es el comportamiento predeterminado, cuando withCredentials
está configurado en false
; por lo tanto, se evita que diferentes dominios establezcan cookies para su propio dominio). La misma withCredentials: true
propiedad debe incluirse en cada solicitud posterior a su API, si desea que la cookie se envíe al servidor, para que el usuario pueda autenticarse y proporcionar acceso a rutas protegidas.
Por lo tanto, una solicitud de Axios que incluya credenciales debería verse así:
await axios.post(url, data, {withCredentials: true}))
El equivalente en una fetch()
solicitud (es decir, usando Fetch API ) es credentials: 'include'
. El valor predeterminado para credentials
es same-origin
. El uso credentials: 'include'
hará que el navegador incluya credenciales tanto en solicitudes del mismo origen como de orígenes cruzados, así como también establecerá cualquier cookie enviada de vuelta en respuestas de orígenes cruzados. Por ejemplo:
fetch('https://example.com', {
credentials: 'include'
});
Nota IMPORTANTE
Dado que está realizando una solicitud de origen cruzado, para que lo anterior funcione, deberá especificar explícitamente los orígenes permitidos, como se describe en esta respuesta (entre bastidores, es decir, configurar el Access-Control-Allow-Origin
encabezado de respuesta). Por ejemplo:
origins = ['http://localhost:3000', 'http://127.0.0.1:3000',
'https://localhost:3000', 'https://127.0.0.1:3000']
Usar el *
comodín en su lugar significaría que se permiten todos los orígenes; sin embargo, eso también permitiría solo ciertos tipos de comunicación, excluyendo todo lo que involucre credentials
, como cookies , encabezados de autorización , etc.; por lo tanto, no debe usar el *
comodín.
Además, asegúrese de configurarlo allow_credentials=True
cuando utilice CORSMiddleware
(que establece el Access-Control-Allow-Credentials
encabezado de respuesta en true
).
Ejemplo (ver aquí ):
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)