You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Go JWT授权问题:Cookie与localStorage不匹配如何解决?

JWT授权验证失败问题解决方案

问题核心

后端JWT中间件仅从Cookie中读取token进行验证,但前端将token存在localStorage中,通过Authorization: Bearer <token>请求头传递,导致请求无法通过验证。


方案1:前端改用Cookie自动传递(推荐,安全性更高)

后端设置的Cookie带有HttpOnly属性,前端JS无法直接读取,但浏览器会自动在同域请求中携带该Cookie。只需调整前端请求配置,确保携带凭证即可:

修改前端React请求代码

useEffect(() => {
  const userId = 'your_user_id_here'; // 替换为实际获取用户ID的逻辑
  const fetchProfile = async () => {
    try {
      const response = await axios.get(`http://127.0.0.1:8080/api/accounts/${userId}`, {
        withCredentials: true // 关键:允许axios携带Cookie
      });
      setProfileData(response.data);
    } catch (error) {
      console.error('Profile fetch error:', error.response ? error.response.data : error.message);
    }
  };
  fetchProfile();
}, []);

跨域场景补充

如果前后端是跨域部署,后端还需配置CORS:

  • 允许Access-Control-Allow-Credentials: true
  • 明确指定允许的Origin(不能使用通配符*)

方案2:重构后端中间件,同时支持Cookie与Bearer Token

若坚持使用localStorage存储token并通过请求头传递,可修改后端中间件,同时兼容两种token获取方式:

修改后端JWT中间件代码

import "strings"

func JWTMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        var tknStr string

        // 优先从Authorization头获取Bearer Token
        authHeader := r.Header.Get("Authorization")
        if authHeader != "" {
            parts := strings.Split(authHeader, " ")
            if len(parts) == 2 && parts[0] == "Bearer" {
                tknStr = parts[1]
            }
        }

        // 若请求头无token,则尝试从Cookie读取
        if tknStr == "" {
            c, err := r.Cookie("token")
            if err != nil {
                if err == http.ErrNoCookie {
                    functionalities.WriteJSON(w, http.StatusUnauthorized, APIServerError{Error: "Unauthorized"})
                    return
                }
                functionalities.WriteJSON(w, http.StatusBadRequest, APIServerError{Error: err.Error()})
                return
            }
            tknStr = c.Value
        }

        claims := &Claims{}
        tkn, err := jwt.ParseWithClaims(tknStr, claims, func(token *jwt.Token) (interface{}, error) {
            if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, http.ErrNotSupported
            }
            return []byte("SECRET"), nil
        })

        if err != nil {
            if err == jwt.ErrSignatureInvalid {
                functionalities.WriteJSON(w, http.StatusUnauthorized, APIServerError{Error: "Unauthorized"})
                return
            }
            functionalities.WriteJSON(w, http.StatusBadRequest, APIServerError{Error: err.Error()})
            return
        }
        if !tkn.Valid {
            functionalities.WriteJSON(w, http.StatusUnauthorized, APIServerError{Error: "Unauthorized"})
            return
        }

        next.ServeHTTP(w, r)
    })
}

配套调整登录接口

登录成功后,除了设置Cookie,还需将token返回给前端,以便存入localStorage:

// 登录接口生成token后
http.SetCookie(w, &http.Cookie{
    Name:     "token",
    Value:    tokenString,
    Expires:  time.Now().UTC().Add(time.Hour),
    HttpOnly: true,
    Secure:   true,
    Path:     "/",
})
// 返回token给前端
functionalities.WriteJSON(w, http.StatusOK, map[string]string{"token": tokenString})

前端登录逻辑补充

// 登录请求示例
axios.post('/api/login', { username, password })
  .then(res => {
    localStorage.setItem('authToken', res.data.token);
  });

内容的提问来源于stack exchange,提问作者srmback

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 15:03:14