【问题标题】:How do you deal with public and private routes in a NextJS app?你如何处理 NextJS 应用程序中的公共和私有路由?
【发布时间】:2021-02-16 02:38:06
【问题描述】:

我正在开发一个具有公共和管理路由的应用程序,在我们过去的 CRA 应用程序中,我们使用了自定义路由元素,但我们在 nextjs 中没有细化...我们有很多公共页面,并且我们有 20 个私人页面/路线。

在 nextjs 中处理受保护的认证路由和公共路由的最佳方法是什么?

非常感谢! 最好的

【问题讨论】:

    标签: reactjs next.js


    【解决方案1】:

    非常感谢@AleXiuS 的回答! 对于那些想要将此 hoc 与 typescript 一起使用的人,我已将您的解决方案和 great article 混合在一起:

    import { NextComponentType } from "next";
    
    function withAuth<T>(Component: NextComponentType<T>) {
      const Auth = (props: T) => {
        // Login data added to props via redux-store (or use react context for example)
        const { isLoggedIn } = props;
    
        // If user is not logged in, return login component
        if (!isLoggedIn) {
          return <Login />;
        }
    
        // If user is logged in, return original component
        return <Component {...props} />;
      };
    
      // Copy getInitial props so it will run as well
      if (Component.getInitialProps) {
        Auth.getInitialProps = Component.getInitialProps;
      }
    
      return Auth;
    }
    
    export default withAuth;
    

    【讨论】:

      【解决方案2】:

      这是typescript版本,你可以将允许的权限传递给HOC,并与登录用户现有的权限进行比较。

      export interface ProtectedComponentProps {
      requiredPermission: string;
      }
      
      const ProtectedComponent: React.FC<ProtectedComponentProps> = (props) => {
      const [isAuthorized, setIsAuthorized] = useState<boolean>();
      useEffect(() => {
          const permissions = authService.getPermissions();
          setIsAuthorized(permissions.includes(props.requiredPermission))
      
      }, []);
      return (
          <>
              {isAuthorized ? props.children : <p>not authorized</p>}
          </>
      
      
      );
      }
      
      export default ProtectedComponent;
      

      并像这样使用它:

       <ProtectedComponent requiredPermission="permissionName">
            <SomeProtectedComponent />
       </ProtectedComponent>
      

      【讨论】:

        【解决方案3】:

        除了使用 HOC 的解决方案之外,您还可以使用接下来的 ssr 方法,例如 getServerSideProps, 在这种情况下,您必须修改您的登录功能以在您的申请中设置标题(此标题将说明您是否已登录) 像这样:

        const signIng = async() =>{
        ...
            api.defaults.headers.someTokenName = token; //Here you can set something just to identify that there is something into someTokenName or your JWT token
        ...
        }
        

        然后在你的 withAuth 组件中:

        const WithAuth = (): JSX.Element => {
          // ... your component code
        }
        
        export const getServerSideProps: GetServerSideProps = async(ctx) => {
          const session = await ctx.req.headers['someTokenName'];
        
         if(!session){
           return{
            redirect:{
              destination: '/yourhomepage', //usually the login page
              permanent: false,
            }
           }
         }
        
         return{
          props: {
           authenticated: true 
          }
         }
        }
        

        这应该可以防止您的 Web 应用程序从未验证到已验证闪烁

        【讨论】:

          【解决方案4】:

          我认为这取决于页面的类型。

          对于静态生成的页面:

          您可以像 @AleXius 建议的那样使用 HOC 进行身份验证。

          对于服务器端呈现的页面:

          您可以在getServerSideProps 中执行您的身份验证逻辑。

          export async function getServerSideProps(context) {
            const sendRedirectLocation = (location) => {
              res.writeHead(302, {
                Location: location,
              });
              res.end();
              return { props: {} }; // stop execution
            };
          
            // some auth logic here
            const isAuth = await authService('some_type_of_token')
          
            if (!isAuth) {
              sendRedirectLocation('/login')
            }
          
            return {
              props: {}, // will be passed to the page component as props
            }
          }
          

          对于带有自定义服务器的服务器端渲染页面:

          取决于您选择的服务器,您可以选择不同的解决方案。对于 Express,您可能可以使用 auth 中间件。如果你愿意,也可以在getServerSideProps处理。

          【讨论】:

          • 在每一页申请getServerSideProps
          • 是的,在你想要 SSR 的每一页上
          • 有没有办法像@AleXiuS 一样将这个逻辑提取到一个 HOC 中?
          • @AseerKTMiqdad 您可以提取要在getServerSideProps 中重用的身份验证逻辑,如Creating a HOC (higher order component) for cookies in nextJS 中所述。
          【解决方案5】:

          我个人一直在为此使用 HOC(高阶组件)。

          这是一个示例身份验证 HOC:

          const withAuth = Component => {
            const Auth = (props) => {
              // Login data added to props via redux-store (or use react context for example)
              const { isLoggedIn } = props;
          
              // If user is not logged in, return login component
              if (!isLoggedIn) {
                return (
                  <Login />
                );
              }
          
              // If user is logged in, return original component
              return (
                <Component {...props} />
              );
            };
          
            // Copy getInitial props so it will run as well
            if (Component.getInitialProps) {
              Auth.getInitialProps = Component.getInitialProps;
            }
          
            return Auth;
          };
          
          export default withAuth;
          

          您可以将此 HOC 用于任何页面组件。 下面是一个使用示例:

          const MyPage = () => (
            <> My private page</>
          );
          
          export default withAuth(MyPage);
          

          如果需要,您可以扩展 withAuth HOC 并使用角色检查,例如公共、普通用户和管理员。

          【讨论】:

          • 这个方法将我的登录页面样式导入到其他所有组件中。
          • 可能是因为“isLoggedIn”布尔值在变为假之前为真?在这种情况下,您还会看到一闪而过的登录页面...如果您在客户端进行身份验证,您可以添加“正在加载”道具并检查它是否也未处于加载状态。
          • 你有打字稿例子吗?
          • URL地址栏显示组件路径但显示需要重定向的登录
          • 这不起作用。
          猜你喜欢
          • 2023-02-03
          • 2016-02-26
          • 1970-01-01
          • 1970-01-01
          • 2021-06-17
          • 2021-11-09
          • 1970-01-01
          • 2014-10-10
          • 1970-01-01
          相关资源
          最近更新 更多