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

IT技术 reactjs gatsby react-context
2021-05-03 10:31:54

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

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

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

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

这是我的 AuthContextProvider 包装类:

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>
    );
  }
}  

我用 Context Provider 在根布局中包装了我的整个应用程序:

const RootLayout = ({ children }) => {
  return (
    <AuthContextProvider>
      {children}
    </AuthContextProvider>
  );
}
3个回答

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

如果您还没有实现您的身份验证层,您将需要研究它是如何工作的。有许多策略可以保持该状态,即使仅在使用基于 cookie 的存储中也是如此。JWT(JSON Web Token)是一种流行的方法,它可以让您将签名的用户和客户端可读数据存储在 cookie 中,但需要做更多的工作来管理到期/续订并拥有更大的有效负载。假设这是您采用的方法,您可能会执行以下操作:

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>
    );
  }
}

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

您可能希望App使用此组件包装 Gatsby ,您可以从gatsby-browser.jsgatsby-ssr.js文件中执行此操作(如果您还没有它们,请在您的存储库的根目录中创建它们):

// 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 的创建您的应用程序生命周期。

我希望这对您或其他人有所帮助。下面的博客文章描述了您需要如何使用 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)(最安全,需要后端服务器)

关于背景信息的一个很好的读物是dev.to 上的这个博客

1. 网络存储,如localStorage

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

这个问题描述了如何使用它:

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,您可以使用express-ession. 其他 Web 服务器也有类似的中间件。关键是在 cookie 中提供用户信息,如MDN 上所述

3.json网络令牌

这类似于 cookie,但使用 JSON Web 令牌。@coreyward 给出了一个很好的答案。您还可以在这篇博文中阅读更多内容