【问题标题】:React flashing Private Route when User is not authenticated当用户未通过身份验证时反应闪烁的私有路由
【发布时间】:2020-11-12 14:07:27
【问题描述】:

我正在使用react-router-dom 来保护整个应用程序。所有路由都受到 ProtectedRoute 组件的保护(参见下面的代码),如果用户未登录,该组件将重定向到外部 url,即单点登录 (SSO) 页面。

问题:

当用户转到“/home”时,他们会在被重定向到“external-login-page.com/”(登录页面)之前对受保护的路由有一个简短的了解(“闪光”)。如何避免闪烁,让用户只看到登录页面?

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
  isAuthenticated,
  ...rest
}) => {
  if (!isAuthenticated) { // redirect if not logged in
    return (
      <Route
        component={() => {
          window.location.href = 'http://external-login-page.com/';
          return null;
        }}
      />
    );
  } else {
    return <Route {...rest} />;
  }
};

【问题讨论】:

  • 你的意思是代码以某种方式执行else 语句一小会儿?
  • @thk_ 你的问题解决了吗?

标签: reactjs react-router react-router-dom


【解决方案1】:

window.location.href 可以提前调用以防止闪烁。同样在您的特定情况下,您可能想要的是在用户未通过身份验证时根本不呈现任何内容。

代码可能如下所示:

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
  isAuthenticated,
  ...rest
}) => {
  if (!isAuthenticated) { // redirect if not logged in
    window.location.href = 'http://external-login-page.com/';
    return null;
  } else {
    return <Route {...rest} />;
  }
};

【讨论】:

    【解决方案2】:

    您可以考虑Redirect 组件

    export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
      isAuthenticated,
      ...rest
    }) => {
      if (!isAuthenticated) { 
        return <Redirect to='https://external-login-page.com/' />
      } else {
        return <Route {...rest} />;
      }
    };
    
    

    我猜想直接调用 window + return null 会在页面重新加载之前渲染 React 应用程序。

    【讨论】:

      【解决方案3】:

      您可以像这样以更简单的方式使用重定向组件。

        export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
            isAuthenticated,
             children,
            ...rest
          }) => {
               return <Route {...rest} render={() => isAuthenticated ? children : <Redirect to='http://external-login-page.com/' />}
          }
      

      【讨论】:

        【解决方案4】:

        发布最终对我有用的解决方案:而不是由Router 阻止,而是由App 阻止。

        关键是将您的App 分成两个部分,AuthenticatedAppUnauthenticatedApp。从那里,根据用户的访问级别延迟加载正确的组件。这样,如果他们没有被授权,他们的浏览器甚至都不会加载AuthenticatedApp

        • AuthenticatedApp 是您的整个应用程序、提供程序、路由器等的一个组件。您在 App.tsx 中的所有内容都应该放在此处。
        • UnauthenticatedApp 是您希望用户在不允许他们访问应用程序时看到的组件。类似“未授权。请联系管理员寻求帮助。”

        App.tsx

        const AuthenticatedApp = React.lazy(() => import('./AuthenticatedApp'));
        const UnauthenticatedApp = React.lazy(() => import('./UnauthenticatedApp'));
        
        // Dummy function to check if user is authenticated
        const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
        const getUser = () => sleep(3000).then(() => ({ user: '' }));
        
        const App: React.FC = () => {
          // You should probably use a custom `AuthContext` instead of useState,
          // but I kept this for simplicity.
          const [user, setUser] = React.useState<{ user: string }>({ user: '' });
        
          React.useEffect(() => {
            async function checkIfUserIsLoggedInAndHasPermissions() {
              let user;
              try {
                const response = await getUser();
                user = response.user;
                console.log(user);
                setUser({ user });
              } catch (e) {
                console.log('Error fetching user.');
                user = { user: '' };
                throw new Error('Error authenticating user.');
              }
            }
            checkIfUserIsLoggedInAndHasPermissions();
          }, []);
        
          return (
            <React.Suspense fallback={<FullPageSpinner />}>
              {user.user !== '' ? <AuthenticatedApp /> : <UnauthenticatedApp />}
            </React.Suspense>
          );
        };
        
        export default App;
        
        

        在此处阅读 Kent C Dodd 的精彩文章 [0]!

        编辑:找到另一个使用类似方法的好例子,但更复杂一些 - [1]

        [0]https://kentcdodds.com/blog/authentication-in-react-applications?ck_subscriber_id=962237771 [1]https://github.com/chenkie/orbit/blob/master/orbit-app/src/App.js

        【讨论】:

          猜你喜欢
          • 2021-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-19
          • 2017-09-26
          • 2022-08-15
          • 1970-01-01
          • 2019-03-01
          相关资源
          最近更新 更多