【发布时间】:2021-10-15 09:08:18
【问题描述】:
请参考以下代码:
Auth.tsx
import { createContext, useEffect, useState, useContext, FC } from 'react';
interface Props {
// any props that come into the component
}
export const PUBLIC_ROUTES = ['/', '/admin/login'];
export const isBrowser = () => typeof window !== 'undefined';
const AuthContext = createContext({
isAuthenticated: false,
isLoading: false,
user: {},
});
export const useAuth = () => useContext(AuthContext);
export const AuthProvider: FC<Props> = ({ children }) => {
const [user, setUser] = useState({});
const [isLoading, setLoading] = useState(true);
useEffect(() => {
async function loadUserFromCookies() {
// const token = Cookies.get('token');
// TODO: Get the token from the cookie
const token = true;
if (token) {
// console.log("Got a token in the cookies, let's see if it is valid");
// api.defaults.headers.Authorization = `Bearer ${token}`;
// const { data: user } = await api.get('users/me');
// if (user) setUser(user);
}
setLoading(false);
}
loadUserFromCookies();
}, []);
return (
<AuthContext.Provider
value={{ isAuthenticated: !!Object.keys(user).length, user, isLoading }}
>
{children}
</AuthContext.Provider>
);
};
export const ProtectRoute: FC<Props> = ({ children }) => {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) {
return <div>Loading</div>;
}
if (PUBLIC_ROUTES.includes(window.location.pathname)) {
return <>{children}</>;
}
// If the user is not on the browser or not authenticated
if (!isBrowser() || !isAuthenticated) {
window.location.replace('/login');
return null;
}
return <>{children}</>;
};
_app.tsx
import React from 'react';
import Head from 'next/head';
import { AppProps } from 'next/dist/next-server/lib/router/router';
import { ThemeProvider, StyledEngineProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import theme from '../utils/theme';
import { AuthProvider, ProtectRoute } from 'contexts/auth';
export default function MyApp(props: AppProps) {
const { Component, pageProps } = props;
React.useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles && jssStyles.parentElement) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
return (
<React.Fragment>
<Head>
<title>Next App</title>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<AuthProvider>
<ProtectRoute>
<Component {...pageProps} />
</ProtectRoute>
</AuthProvider>
</ThemeProvider>
</StyledEngineProvider>
</React.Fragment>
);
}
问题:
- 因此,根据代码,如果用户未登录,则重定向用户 到登录页面。但是,由于当前的逻辑,404 页 路由也被重定向到管理员登录页面。我怎么能抓住 将 404 状态重定向到 404 页面,然后再验证是否 用户是否登录?
- 我正在使用一个数组来验证路径是否是公共的。有没有
在不维护硬编码的情况下呈现公共路径的更好方法
页面路径还是使用 HOC?我的方法的问题是,如果任何开发人员更改了文件名,并且如果它与数组中的字符串不匹配,那么它将不是公共路由。如果我在其中创建一个名为 public 的文件夹和所有公共页面,我会在我的 URL 中得到一个不必要的
public/。我不想使用 HOC,因为每次创建新页面时我都必须导入它们,这并不正确,但我期待更好的方法。
谢谢。
【问题讨论】:
标签: javascript reactjs authentication routes next.js