我正在将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>
);
}
}
我将整个应用程序和上下文提供程序一起包装在根目录中:
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>
);
}
答案 0 :(得分:1)
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>
);
}
}
这将在安装AuthContextProvider时解析session
cookie中的JWT令牌,并使用存储在JWT中的userid
值更新状态。
您可能想用此组件包装Gatsby 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的创建。应用程序生命周期中的相关点。
答案 1 :(得分:1)
我希望这对您或其他人有帮助。下面的博客文章介绍了如何使用gatsby-browser.js将根元素包装在提供程序中,以免在页面更改时将其重置。
https://www.gatsbyjs.org/blog/2019-01-31-using-react-context-api-with-gatsby/
答案 2 :(得分:0)
this blog on dev.to是有关背景信息的绝佳读物。
这被认为是最不安全的选项。不要在此处保存个人数据,例如电子邮件地址。永远不要保存诸如信用卡信息之类的敏感信息。
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));
对于Express,您可以使用express-ession
。其他Web服务器具有类似的中间件。关键是要按照MDN所述,在Cookie中提供用户信息。
这类似于Cookie,但使用JSON网络令牌。 @coreyward给出了一个很好的答案。您还可以在this blog post中阅读更多内容。