reactjs - 为什么我的 cookie 没有被发送? ReactJS 前端,Go 后端

标签 reactjs cookies jwt go-fiber

我正在开发一个带有 Go 后端(go-fiber 框架)和 ReactJS 前端的个人理财应用程序。

我的身份验证方法是在用户登录时返回一个 JWT 作为 cookie。

前端使用 fetch 发送登录请求,然后跟进另一个 fetch获取用户数据。 fetch调用以及服务器处理函数可以在这个问题末尾的附录中找到。

当我对此进行测试时,我成功登录了。返回一个 Set-Cookie header ,我在响应中看到了我所期望的 cookie。但是,JWT 未作为 header 包含在用户数据请求中。处理程序返回 {"status": "unauthorized"}因为解析的 JWT 是 nil .

为什么 JWT 没有包含在用户数据请求中?

这是 Set-Cookie header ,以及所有登录响应 header 的屏幕截图。 jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDY1MTczOTMsImlzcyI6IjE3In0.SDKnxjsVImuVOHw_hnsPX1ZhtS7-_6s8Cqk79SwniCY; expires=Sat, 05 Mar 2022 21:56:33 GMT; path=/; HttpOnly; SameSite=Lax

Sign-In Response Headers

这是登录时返回的 JWT cookie,以及来自 Chrome 开发者工具的 cookie 的屏幕截图。 jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDY1MTczOTMsImlzcyI6IjE3In0.SDKnxjsVImuVOHw_hnsPX1ZhtS7-_6s8Cqk79SwniCY localhost / 2022-03-05T21:56:33.000Z 195 ✓ Lax Medium

Sign-In Response Cookie

我在“应用程序”选项卡的“Cookies”部分没有看到任何内容。但是,我在其他地方读到我不应该期望看到任何带有 httpOnly 的 cookie。在这里设置为真。

Application Cookies

我希望在用户数据请求中看到一个名为“Cookies”的 header 。但我只看到这些:

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: localhost:9000
Origin: http://localhost:3000
Referer: http://localhost:3000/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36

User Data Request Headers

非常感谢任何插入或帮助。以下是前端和后端代码的 GitHub 页面链接,以帮助解释问题:

ReactJS Front-End

Go-Fiber Back-End

附录

登录请求 fetch :

        fetch('http://localhost:9000/signIn', requestOptions)
            .then(res => {
                if (res.status === 200) {
                    res.json()
                        .then(
                            (result) => {
                                if (result.status && result.status === "success") {
                                    this.props.onRouteChange('home');
                                } else {
                                    // TO DO: display failure message on UI
                                    console.log('Failed to sign in');
                                }
                            },
                            (error) => {
                                this.setState({
                                    isLoaded: true,
                                    error
                                });
                            }
                        );
                } else {
                    console.log('Error signing in');
                    res.json()
                        .then(
                            (result) => {
                                console.log(result);
                            },
                            (error) => {
                                console.log('Error reading JSON of response with status !== 200');
                                console.log(error);
                            }
                        );
                }
            });

登录处理函数:

func handleSignIn(c *fiber.Ctx) error {
    // unmarshal received sign in data into User struct
    var signIn User
    if err := c.BodyParser(&signIn); err != nil {
        err = fmt.Errorf("failed to process HTTP request body to /signIn: %w", err)
        log.Println("Error:", err)
        c.Status(fiber.StatusBadRequest)
        return err
    }

    // look for the identified user in the users database
    usr, err := getUserByUsername(signIn.Username)
    if err != nil && err == sql.ErrNoRows {
        log.Println("Error: user", signIn.Username, "attempted to sign in but not found in users database")
        c.Status(fiber.StatusBadRequest)
        return fmt.Errorf("invalid username/password combination")
    }
    if err != nil {
        err = fmt.Errorf("failed to query database for user %s: %w", signIn.Username, err)
        log.Println("Error:", err)
        c.Status(fiber.StatusInternalServerError)
        return err
    }

    // hash the given password for comparison with the recorded password
    err = bcrypt.CompareHashAndPassword([]byte(usr.Password), []byte(signIn.Password))
    if err != nil {
        log.Println("CompareHashAndPassword returned error during sign in attempt:", err)
        c.Status(fiber.StatusBadRequest)
        return fmt.Errorf("invalid username/password combination")
    }

    // declare claims for the JWT that will be sent back
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
        Issuer:    strconv.Itoa(int(usr.Id)),
        ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // 1 day
    })
    if token == nil {
        err = fmt.Errorf("failed to instantiate JWT")
        log.Println("Error:", err)
        c.Status(fiber.StatusInternalServerError)
        return err
    }

    // encrypt the JWT with the private key
    tokenString, err := token.SignedString([]byte(jwtPrivateKey))
    if err != nil {
        err = fmt.Errorf("failed to encrypt JWT: %w", err)
        log.Println("Error:", err)
        c.Status(fiber.StatusInternalServerError)
        return err
    }

    c.Cookie(&fiber.Cookie{
        Name:     "jwt",
        Value:    tokenString,
        Expires:  time.Now().Add(time.Hour * 24),
        HTTPOnly: true,
    })

    // send response
    return c.JSON(fiber.Map{
        "status": "success",
    })
}

用户数据请求获取:

    componentDidMount() {
        fetch("http://localhost:9000/getExpenses")
            .then(res => res.json())
            .then(
                (result) => {
                    if (result.status !== null && result.status === "unauthorized") {
                        console.log('Failed authorization when requesting expenses!');
                    } else if (result.expenses === null) {
                        console.log('Response did not contain expenses map');
                    } else {
                        this.setState({
                            isLoaded: true,
                            expenses: result.expenses
                        });
                    }
                },
                (error) => {
                    this.setState({
                        isLoaded: true,
                        error
                    });
                }
            );
    }

用户数据请求处理程序:

func handleGetExpenses(c *fiber.Ctx) error {
    // parse JWT from HTTP cookie
    token, err := parseCookie(c)
    if err != nil {
        c.Status(fiber.StatusUnauthorized)
        return c.JSON(fiber.Map{
            "status": "unauthorized",
        })
    }

    // check which user is getting their expenses
    claims := token.Claims.(*jwt.StandardClaims)
    userId, err := strconv.ParseInt(claims.Issuer, 10, 64)
    if err != nil {
        err = fmt.Errorf("invalid Issuer field in JWT")
        log.Println("Error:", err)
        c.Status(fiber.StatusUnauthorized)
        return err
    }

    // get all expenses from the database
    expenses, err := getAllExpenses(userId)
    if err != nil {
        err = fmt.Errorf("failed to get expenses from expense table: %w", err)
        log.Println("Error:", err)
        c.Status(fiber.StatusInternalServerError)
        return err
    }

    // send response
    return c.JSON(fiber.Map{
        "expenses": expenses,
    })
}

最佳答案

默认情况下,fetch 不使用 cookie。您可以像这样使 fetch 使用 cookie:

fetch(url, {
  credentials: "same-origin",
}).then(responseHandler).catch(errorHandler);

您可以查看文档以获取更多详细信息: https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters

关于reactjs - 为什么我的 cookie 没有被发送? ReactJS 前端,Go 后端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71357981/

相关文章:

c# - 如何保持登录 Awesomium?

javascript - 为什么在页面转换时不调用 next-auth jwt 回调?

angularjs - 从 JWT token 检索 Azure 组详细信息

javascript - 在 react 状态下用数组替换字符串时出错

javascript - 为什么我的嵌套组件会自行重建?

django - Tornado、Django、Websockets 和 session 同步

rest - go-restful + JWT认证

reactjs - 如何将 React 应用程序与 rollup 捆绑在一起

javascript - Recharts 在 React 中不起作用 - 'recharts' 不包含名为 'Recharts' 的导出

Java小程序获取文档cookie?