当用户未经身份验证时反应闪烁的专用路由

tki*_*m90 5 reactjs react-router react-router-dom

我用来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} />;
  }
};
Run Code Online (Sandbox Code Playgroud)

tki*_*m90 1

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

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

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

应用程序.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;

Run Code Online (Sandbox Code Playgroud)

在这里阅读 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