我将Gatsby用作静态网站生成器。我使用React Context API来存储用户已通过身份验证的信息。
在开发模式下,当我键入任何重定向到404错误页面的URL时,上下文数据将丢失。当我导航到有效页面时,以前登录的用户不再登录。
我之前从未使用过React Context,所以我不确定该怎么做。那是预期的行为吗?有什么方法可以保留用户特定的React Context?我是否需要从后端重新提供上下文?还是我只是犯了一个错误?最好的行动方针是什么?
我想以某种方式将上下文保留在浏览器中,直到会话超时。尚未执行来自后端的会话处理。
编辑: 我刚刚用gatsby构建和gatsby服务测试了这一点。当重定向到404错误页面时,内置的gatsby网站会保留上下文。但是,当导航到完全不同的URL(例如www.google.com)时,上下文仍然丢失。
现在我的问题是:如何在不让用户再次手动登录的情况下为上下文提供登录信息? Cookie检查?抱歉,如果我要问一个明显的问题。我从未实现过会话或cookie。
这是我的AuthContextProvider包装器类:
import React from "react"; export const AuthContext = React.createContext(); export class AuthContextProvider extends React.Component { state = { authenticated: false, toggleLogin: () => {}, userid: null, }; render() { return ( <AuthContext.Provider value={{ authenticated: this.state.authenticated, userid: this.state.userid, toggleLogin: () => { const previousValueState = this.state.authenticated; this.setState(state => ({ authenticated: !previousValueState, userid: 2, })); }, }} > {this.props.children} </AuthContext.Provider> ); } }
我用Context Provider将整个应用程序包装在根布局中:
export default function RootLayout({ children }) { return ( <React.Fragment> <Helmet> <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,600&display=swap" /> </Helmet> <GoogleReCaptchaProvider reCaptchaKey={recaptchaSiteKey}> <ThemeProvider theme={theme}> <CssBaseline /> <AuthContextProvider> {children} </AuthContextProvider> </ThemeProvider> </GoogleReCaptchaProvider> </React.Fragment> ); }
React Context是关于向一个或多个子组件提供一些数据,而不必通过中间组件向下传递数据。没有内置的机制可以在页面加载之间持久保存状态,因此您需要为此使用另一种工具。
如果您尚未实现身份验证层,则需要研究其工作原理。有许多策略可以保持该状态,即使只是在使用基于cookie的存储中也是如此。JWT(JSON Web令牌)是一种流行的方法,它使您可以将已签名的用户和客户端可读数据存储在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中的值更新状态(如果存在)。
session
userid
您可能会想App用此组件包装Gatsby ,可以从gatsby-browser.js和gatsby- ssr.js文件中进行包装(如果还没有文件,请在仓库的根目录中创建它们):
App
gatsby-browser.js
gatsby- 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的创建。您的应用程序生命周期。