浏览器未保存Golang后端发送的cookie

f87krz0w  于 2022-12-30  发布在  Go
关注(0)|答案(1)|浏览(141)

我知道这个问题已经被问过很多次了,但是我试过了大多数的答案,仍然不能让它起作用。
我有一个带有net/http包的Golang API和一个JS前端。我有一个函数

func SetCookie(w *http.ResponseWriter, email string) string {
    val := uuid.NewString()
    http.SetCookie(*w, &http.Cookie{
        Name:     "goCookie",
        Value:    val,
        Path:     "/",
    })
    return val
}

这个函数在用户登录时被调用,我希望它被发送到所有其他端点,这在Postman中也能正常工作,但是,当涉及到浏览器时,我似乎无法让它记住cookie,甚至无法将其发送到其他端点。
使用端点的JS示例

async function getDataWithQuery(query, schema){
    
    let raw = `{"query":"${query}", "schema":"${schema}"}`;
    let requestOptions = {
        method: 'POST',
        body: raw,
        redirect: 'follow',
    };
    try{
        let dataJson = await fetch("http://localhost:8080/query/", requestOptions)
        data = await dataJson.json();
    }catch(error){
        console.log(error);
    }

    return data;
}

我尝试过在Golang中设置SameSite属性,或者在JS中使用credential: "include",但没有成功。

sg3maiej

sg3maiej1#

多亏了评论中的讨论,我发现了一些关于这个问题的提示。

保存cookie(API和前端在同一主机上)

我使用document.cookie来保存cookie。我手动设置选项,因为在API fetch的响应上调用res.cookie只返回值。document.cookie =goCookie=${res.cookie}; path=/; domain=localhost;`就是一个例子。

发送cookie

这在之前的问题中已经回答过了,在评论中又回答了一次,问题是我用了credential:'include'而不是正确的credentials:'include'(复数)。

CORS和Cookie

如果API和前端不在同一主机上,则必须同时修改API和前端。

前端

Cookie必须具有API的域,因为是API而不是前端需要它。因此,出于安全原因,你不能为域设置cookie(API)从另一个域一个解决方案是将用户重定向到一个API端点,该端点在响应头中返回Set-Cookie头。此解决方案向浏览器发出信号,以向附加到该cookie的域注册该cookie(API的域,因为是API发送的)。
此外,您仍然需要在前端中包含credentials:'include'

API

你需要设置一些头文件,我设置的是

w.Header().Set("Access-Control-Allow-Origin", frontendOrigin)
    w.Header().Set("Access-Control-Allow-Credentials", "true")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type, withCredentials")
    w.Header().Set("Access-Control-Allow-Methods", method) // use the endpoint's method: POST, GET, OPTIONS

你需要公开前端将重定向用户的端点,并在响应中设置cookie,而不是手动设置API的域,你可以省略它,浏览器将自动用域填充它。
要处理CORS并让JS成功发送cookie,您必须在cookie中设置SameSite=NoneSecure属性,并通过https提供API(我使用了ngrok使其简单化)。
像这样

func SetCookie(w *http.ResponseWriter, email string) string {
    val := uuid.NewString()
    http.SetCookie(*w, &http.Cookie{
        Name:     "goCookie",
        Value:    val,
        SameSite: http.SameSiteNoneMode,
        Secure:   true,
        Path:     "/",
    })
   // rest of the code
}

我建议您也阅读使用localStoragedocument.cookie之间的区别,这是我遇到的问题之一。
希望这个有用。

相关问题