redux 如何在React中获取HTTP专用Cookie?

fd3cxomn  于 2022-11-12  发布在  React
关注(0)|答案(4)|浏览(166)

我目前正在开发一个MERN堆栈应用程序,我使用的身份验证是JWT,并将其保存在我的cookie中。

res
                .cookie("token", token, {
                  httpOnly: true,
                  secure: true,
                  sameSite: "none",
                })
                .send();

而且我通过在我的后端获得“令牌”cookie来登录用户。然而,我用这个应用程序实现了Redux,每次我刷新页面时,它会自动退出。我想要的是在我的前端检测(React)我的浏览器中的“token”cookie无法获取。我尝试使用npm js-cookie,但仍然无法获取。是否有方法可以获取“token”cookie?或者根据我读到的内容使用redux-persistent?请帮助,谢谢。

n3ipq98p

n3ipq98p1#

就像其他答案已经解释的那样,你不能通过JS访问httpOnly cookie。
我个人建议你使用不同的方法。当然,cookie和httpOnly听起来是个好主意,你可能认为cookie比localStorage好一千倍,但最终,你是把令牌存储在localStorage还是cookie中并不重要。你可能会为cookie和localStorage争论几个小时,但两者都有它们的漏洞(例如:Cookie:CSRF攻击(https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html),本地存储:XSS)的数据。
现在,虽然理论上可以在这里使用localStorage,但我并不提倡使用它。(可以是context-api、redux等),并将带有身份验证头的JWT发送到后端。当然,后端需要验证该令牌。您可以,例如,只需实现一个身份验证中间件,并将其添加到所有需要身份验证的路由中。过期也非常简单,因为您不必再同步JWT和cookie的过期。只需在JWT上设置过期,身份验证中间件中的令牌验证就会捕获它。如果您想知道为什么此方法可以安全地抵御CSRF攻击,请看这里:Where to store JWT in browser? How to protect against CSRF?
这里有一些好文章,我真的会推荐你读一点的第一个:https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/https://medium.com/@ryanchenkie_40935/react-authentication-how-to-store-jwt-in-a-cookie-346519310e81打印机

t1qtbnec

t1qtbnec2#

你不能。“httpOnly”意味着“JavaScript不能访问它”。
使用Redux-Persist也不能真正帮助您确定您是否仍处于登录状态或您的会话是否超时。这些数据可能在几周前就已被持久化,或者令牌可能已被吊销。
最明智的做法是在服务器上设置一个/whoami端点,并作为应用程序初始化时的第一步,向服务器发送一个请求。要么返回用户信息-〉太好了,保存并显示它。否则,您会得到一个“401未授权”,这意味着用户没有登录,需要登录。

68bkxrlz

68bkxrlz3#

虽然您不能在前端对httpOnly cookie做任何事情,但肯定有一种方法可以处理前端发送的httpOnly cookie,并从该cookie中提取您的JWT,所有这些都在MERN堆栈应用程序的后端。
至于持久化用户并防止"logout upon refresh“问题,您将必须创建一个useEffect钩子来不断地检查令牌是否存在--我们将在后面讨论这个问题。
首先,我建议在后端使用Cors:

const cors = require("cors");

app.use(
  cors({
    origin: ["http://...firstOrigin...", ...],
    credentials: true,
  })
);

准备就绪后,在创建httpOnly cookie时设置以下选项。此外,如果是JWT,则创建一个非httpOnly cookie,它使用相同的过期日期和布尔值跟踪httpOnly cookie。这将允许您使用'universal-cookie'库并实际读取前端中的非httpOnly cookie:

res
                .cookie("token", token, {
                  origin: "http://...firstOrigin..."
                  expires: // set desired expiration here
                  httpOnly: true,
                  secure: true,
                  sameSite: "none",
                })
                .cookie("checkToken", true, {
                  origin: "http://...firstOrigin..."
                  expires: // same as above
                  secure: true,
                  sameSite: "none",
                })

创建了一个模仿我们实际'token'的'checkToken' cookie后,我们可以使用它来设置状态(useState钩子),如果用户存在且未过期,则可以通过useEffect钩子来持久保存用户。
但是,要正确地发送它,我们必须先指定几件事,在这个例子中,我将使用axios在前端进行这样的API调用。
请注意,每个API调用的请求头将包含我们的httpOnly cookie及其内容-我们可以通过打开chrome开发工具的网络选项卡来确认这一点,进行API调用,然后检查“请求头”中的“Cookie”...

const cookies = new Cookies();
const checkToken = cookies.get("checkToken");

const AuthUser = () => {
  const [user, setUser] = useState(checkToken);

  useEffect(() => {
    async function checkToken() {
      await axios
        .post("http://...yourBackend.../authToken", {
          withCredentials: true,    // IMPORTANT!!!
        })
        .then((res) => {
          // handle response - if successful, set the state...
          // to persist the user
        )}
        .catch((err) => {
          // handle error
        )}
    };

    checkToken();
  }, []);

  // Implement your login behavior here
}

完成后,我们可以确认在后端的API调用的请求主体中获得了这样的令牌(无论在哪里处理),在控制台中记录cookie以检查它,然后将cookie的值存储在一个变量中以启用对所述cookie的验证:

app.post(".../authToken", (req, res) => {
  // Get all cookies from request headers
  const { cookie } = req.headers;

  // Check to see if we got our cookies
  console.log(cookie);   

  // Handle this as you please
  if (cookie == undefined) return;

  const token = cookie.split("token=")[1].split(";")[0];   // Yep, it's a string
  console.log(token);    // Check to see if we stored our cookie's JWT

  // Some middleware:

  jwt.verify(token, process.env.TOKEN, (err, user) => {
    // if success upon verification,
    // issue new 'token' and 'checkToken'
  });
});

好了,好了
请注意,这是一个一般的实现,只是作为一个指南,以了解httpOnly cookie的功能。OP从来没有提供原始代码去关闭。
希望这能帮上忙,祝你成功。

l3zydbqr

l3zydbqr4#

我们遇到了类似的问题提高授权工作流的安全性在一个项目上使用React/Django创建时
问题是:存储JWT的最佳位置是什么?
经过研究,我们最终实现了Oauth2协议,本文将帮助您了解Refresh token rotation的逻辑
我们的实施
1.在后端生成2个令牌(访问令牌[短寿命]和刷新令牌[长寿命])
1.刷新标记应存储在HttpOnly cookie中(正如他们在响应中提到的,JS无法在客户端访问它)
1.在前端级别,我们仅使用访问令牌,当它过期时,我们调用后端以重新生成另一个访问和刷新
1.后端将访问HttpOnly Cookie中的刷新令牌,并确定它是否有效,以生成新令牌
1.如果后端生成新的有效令牌,则将访问令牌发送到前端,并更新Cookie中的刷新令牌
Ps:通过这个逻辑,你没有权限在前端刷新令牌,所以当你的访问令牌不再有效时,你告诉服务器检查存储在HttpOnly Cookie中的刷新令牌,如果它仍然有效,然后重新生成其他有效令牌
我希望这能启发你

相关问题