如何在 Gatsby 站点中保留或重新提供 React Context

How to keep or resupply React Context in a Gatsby site

我使用 React Context API 来存储用户已通过身份验证的信息。

在开发模式下,当我输入任何重定向到 404 错误页面的 URL 时,上下文数据都会丢失。当我导航到一个有效页面时,以前登录的用户不再登录。

编辑: 我刚刚用 gatsby build 和 gatsby serve 测试了这个。构建的 gatsby 站点在重定向到 404 错误页面时会保留上下文。但是当导航到完全不同的 URL 例如 www.google.com.

时上下文仍然丢失

现在我的问题是:如何在不让用户再次手动登录的情况下为上下文重新提供登录信息?

这是我的 AuthContextProvider 包装器 class:

export class AuthContextProvider extends React.Component {
  constructor(props) {
    super(props);
    this.state = { user: {} };
  }
  
  // ...
  
  render() {
    return (
      <AuthContext.Provider value={{ getUser: this.getUser, setUser: this.setUser }}>
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}  

我用根布局中的上下文提供程序包装我的整个应用程序:

const RootLayout = ({ children }) => {
  return (
    <AuthContextProvider>
      {children}
    </AuthContextProvider>
  );
}

React Context 是关于向一个或多个子组件提供一些数据,而不必通过中间组件向下传递数据。没有 built-in 机制可以在页面加载之间保持状态,因此您需要为此使用其他工具。

如果您还没有实现身份验证层,您将需要了解它的工作原理。有许多策略可以维持该状态,即使只是在使用 cookie-based 存储时也是如此。 JWT(JSON Web 令牌)是一种流行的方法,它可以让您在 cookie 中存储签名用户和 client-readable 数据,但代价是需要更多的工作来管理 expiration/renewal 并拥有一个更大的有效载荷。假设这是您采用的方法,您可能会这样做:

import React from "react";
import jwt from "jsonwebtoken"; // Add jsonwebtoken via npm/yarn

function getCookieValue(a) {
  var b = document.cookie.match('(^|[^;]+)\s*' + a + '\s*=\s*([^;]+)');
  return b ? b.pop() : '';
}

const AUTH_PUBLIC_KEY = "your JWT public key here"

export const AuthContext = React.createContext();

export class AuthContextProvider extends React.Component {
  state = {
    authenticated: false,
    userid: null,
  };

  componentDidMount() {
    jwt.verify(getCookieValue("session"), AUTH_PUBLIC_KEY, (err, session) => {
      if (!err && session.userid) {
        this.setState({ userid: session.userid, authenticated: true })
      }
    })
  }

  // Important: REMOVE THIS AFTER TESTING/DEV
  toggleLogin = () => {
    this.setState(state => ({
      authenticated: !state.authenticated,
      userid: 2,
    }));
  }

  render() {
    return (
      <AuthContext.Provider
        value={{
          ...this.state,
          toggleLogin: this.toggleLogin,
        }}
      >
        {this.props.children}
      </AuthContext.Provider>
    );
  }
}

这将在安装 AuthContextProvider 时解析 session cookie 中的 JWT 令牌,并使用存储在 JWT 中的 userid 值更新状态(如果存在)。

你可能想用这个组件包装 Gatsby App,你可以从 gatsby-browser.jsgatsby-ssr.js 文件中完成(如果你在你的 repo 的根目录中创建它们还没有):

// gatsby-browser.js
import React from "react"
import AuthContextProvider from "components/AuthContextProvider"

export const wrapRootElement = ({ element }) =>
  <AuthContextProvider>{element}</AuthContextProvider>

// gatsby-ssr.js
import React from "react"
export { wrapRootElement } from "./gatsby-browser"

您仍然需要处理生成 JWT 令牌(可能来自处理身份验证的后端),如果它尚未保存在您可以从浏览器访问的 cookie 中,您将需要处理该 cookie 的创建在您的应用程序生命周期的相关点。

希望对您或其他人有所帮助。下面的博客 post 描述了您需要如何使用 gatsby-browser.js 将根元素包装在提供程序中,以便它不会在页面更改时重置它。

https://www.gatsbyjs.org/blog/2019-01-31-using-react-context-api-with-gatsby/

你有 3 种可能性:

  1. 网络存储又名 localStorage 或 sessionStorage(最简单,最不安全)
  2. 会话 cookie(安全,需要后端服务器)
  3. json 网络令牌 (JWT)(最安全,需要后端服务器)

有关背景信息的优秀读物是 this blog on dev.to

1。网络存储,例如 localStorage

这被认为是最不安全的选项安全选项。不要在此处保存电子邮件地址等个人数据。永远不要保存敏感信息,例如信用卡信息等。

This question介绍使用方法:

var testObject = { 'one': 1, 'two': 2, 'three': 3 };

// Put the object into storage
localStorage.setItem('testObject', JSON.stringify(testObject));

// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');

console.log('retrievedObject: ', JSON.parse(retrievedObject));

2。 cookie 或会话 cookie

对于快递,您可以使用 express-ession. Other web servers have similar middleware. The point is to supply the user info within a cookie as described on MDN

3。 json 网络令牌

这类似于 cookie,但使用 JSON 网络令牌。 @coreyward 给出了很好的答案。您还可以在 this blog post.

中阅读更多内容