网站搜索

reactjs - 在 React-Ionic 应用中使用 Firebase 身份验证上下文的受保护路由


我正在尝试在一个带有受保护路由的 React-Ionic 应用中为 Firebase 身份验证设置上下文,这些路由在未认证的情况下不应该被访问到。到目前为止,它有点起作用,但不是完全正常。我可以毫无问题地登录并导航到带受保护路由的页面,但一旦我刷新页面,它就会把我带回登录页,好像我没有认证一样。

我很确定我在某些地方搞砸了,但一直没能发现问题出在哪里(实际上整个实现都有可能是错误的,因为我对此还很新,还在学习中)。

到目前为止,我的文件是这样的(不包括导入之类的,只是核心部分):

App.tsx:

const App: React.FC = () => {

  const authContext = useContext(AuthContext);

  useEffect(() => {
    console.log(authContext) **//**
  }, [])  

  return (
    <IonApp>
      <IonReactRouter>
        <IonRouterOutlet>
          <Route exact path="/" component={PageLogin} />
          <ProtectedRoute path="/secure/home" component={PageHome} isAuthenticated={authContext.authenticated!}/>
          <ProtectedRoute path="/secure/lot/:lotId" component={PageLotOverview} isAuthenticated={authContext.authenticated!}/>
          <ProtectedRoute path="/secure/shipment/:shipmentId" component={PageShipmentOverview} isAuthenticated={authContext.authenticated!}/>
        </IonRouterOutlet>
      </IonReactRouter>
    </IonApp>
  )
}

AuthProvider.tsx:

export const AuthContext = React.createContext<Partial<ContextProps>>({});

export const AuthProvider = ({ children }: any) => {

  const [user, setUser] = useState(null as firebase.User | null);
  const [loadingAuthState, setLoadingAuthState] = useState(true);

  useEffect(() => {
    firebase.auth().onAuthStateChanged((user: any) => {
      setUser(user);
      setLoadingAuthState(false);
    });
  }, []);

  return (
    <AuthContext.Provider
      value={{
        user,
        authenticated: user !== null,
        setUser,
        loadingAuthState
      }}>
      {children}
    </AuthContext.Provider>
  );
}

ProtectedRoute.tsx:

interface ProtectedRouteProps extends RouteProps {
  component: React.ComponentType<any>;
  path: string;
  isAuthenticated: boolean
}


export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ component: Component, path, isAuthenticated }) => {

  useEffect(() => {
    console.log("from protected ROUTE", isAuthenticated)
  }, [])

return (
    <Route path={path} render={() => isAuthenticated ? <Component /> : <Redirect to="/" />} />
  );
};

index.tsx:

ReactDOM.render(
  <AuthProvider>
    <App />
  </AuthProvider>
  , document.getElementById('root'));

如果我可以提供更多有用的信息,请告诉我。提前感谢您的帮助。

答案#1

第一点:每个人仍在学习。

编号2:对此有一个非常简单的解决方案,我个人使用(效果很好)。你可以使用一种叫做“会话存储”的功能。

一旦你从 Firebase 获取到用户数据,就执行以下操作:

// When login is successful

window.sessionStorage.setItem('isLogged', 'true'); 

// This will create a variable with value *true* that 
can be accessed from any page within your website

会话存储就像一个本地数据库,可以存储你想保存的任意数量的值,并且在刷新时不会被清除。但是它是临时的,当用户关闭浏览器窗口时会被清除。

现在在每个受保护的路由上你都可以这样做。

useEffect(() => {
  if(window.sessionStorage.getItem('isLogged') == 'false')
  {
    window.location.href = '/login' // send the user to login page
  }
}, [])

专业提示:

您可以使用此机制为您正在开发的任何内容实现“记住我”选项。在这种情况下,您可能需要使用LocalStorage,它类似于sessionStorage,但即使用户关闭浏览器窗口也不会删除数据。

而且当用户再次访问你的页面时,它会自动将用户重定向到主页面,而无需登录(如果你创建一个 useEffect 来检查的话)。

还有一件事:localStorage 和 sessionStorage 对不同用户是不同的。我浏览器中的 localStorage 或 sessionStorage 中存储的值对你或其他任何人都是不可见的,只有我自己能看到。

就这样