簡體   English   中英

如何動態使用react路由

[英]How to dynamically use react routing

我有一個應用程序,其中我有兩個登錄名,一個用於superAdmin ,另一個用於“Admin”。

  1. 我有幾個頁面一個是常見的(主頁),兩個用戶都有多余的。

  2. 然后我還有其他幾個頁面,其中一些用於admin ,另一些用於superAdmin

  3. 現在,當我打開我的頁面時,我正在嘗試 go '/' 這條路線(我的家鄉路線)。 我想要做什么

  4. 現在,如果我以管理員身份登錄並且管理員用戶在地址欄中鍵入一些superAdmin url,我希望將其重定向到當前管理員路由

  5. superAdmin也一樣

  6. 兩個用戶我都想限制多余的彼此路線

  7. 如果我是管理員用戶或超級管理員用戶並嘗試登錄並嘗試過多的經過身份驗證的路由,我應該重定向到主頁

我做了什么

我在這里創建了一個組件(動態路由),我正在檢查用戶正在嘗試做什么。 在我的路由文件中的 route.js 中,我將 props 作為guestsuperAdminadmin傳遞

動態路由.js 代碼

我已經創建了我的上下文來存儲用戶登錄后

    export default function Dynamicroute(props) {
    const { user } = useAuthState();  // this I am getting from my context
    console.log(user);

    if (props.partner && !user) {
        console.log('admin not logedin');
        return <Redirect to="/admin" />;
    } else if (props.admin && !user) {
        console.log('superAdmin not loged in');
        return <Redirect to="/superAdmin" />;
    } else if (props.admin && user.role === 'admin') {
        console.log('admin logedin');
        return <Redirect to="/admin_home" />;
    } else if (props.admin && user.role === 'superAdmin') {
        console.log('super admin loged in');
        return <Redirect to="/superadmin_home" />;
    } else if (props.guest && user) {
        console.log('guest');
        return <Redirect to="/" />;
    } else {
        return <Route component={props.component} {...props} />;
    }
}

我的 route.js

<DuynamicRoute exact path="/" component={Home} guest />
<DuynamicRoute path="/admin" component={loginAdmin} guest />
<DuynamicRoute path="/superAdmin" component={loginSuperAdmin} guest />
<DuynamicRoute path="/admin_home" component={admin_home} admin/>
<DuynamicRoute path="/superAdmin_home" component={superAdmin_home} superAdmin/>

我面臨的問題

我不知道我面臨的問題是在登錄時將我重定向到該路由但內容未加載如果我在該頁面上控制台某些內容我無法獲得該頁面,則該頁面將變為空白。

我從 25:00 開始關注這個講座

我得到這個空白頁

已編輯

這是我的代碼沙盒

請檢查這個

編輯

管理員和超級管理員將在不同的瀏覽器中登錄,所以如果他們輸入 url 對方的潰敗,只是不希望管理員訪問超級管理員,反之亦然

為了更好地管理和開發程序以及最佳實踐,在 React.js 中進行授權,如下所示:

Codesandbox 演示

首先:您需要一個class來檢查permissionsroutes/pages configs ,如下所示:

class AppUtils {
  static setRoutes(config) {
    let routes = [...config.routes];

    if (config.auth) {
      routes = routes.map((route) => {
        let auth = config.auth ? [...config.auth] : null;
        auth = route.auth ? [...auth, ...route.auth] : auth;
        return {
          ...route,
          auth
        };
      });
    }

    return [...routes];
  }

  static generateRoutesFromConfigs(configs) {
    let allRoutes = [];
    configs.forEach((config) => {
      allRoutes = [...allRoutes, ...this.setRoutes(config)];
    });
    return allRoutes;
  }

  static hasPermission(authArr, userRole) {
    /**
     * If auth array is not defined
     * Pass and allow
     */
    if (authArr === null || authArr === undefined) {
      // console.info("auth is null || undefined:", authArr);
      return true;
    } else if (authArr.length === 0) {
      /**
       * if auth array is empty means,
       * allow only user role is guest (null or empty[])
       */
      // console.info("auth is empty[]:", authArr);
      return !userRole || userRole.length === 0;
    } else {
      /**
       * Check if user has grants
       */
      // console.info("auth arr:", authArr);
      /*
            Check if user role is array,
            */
      if (userRole && Array.isArray(userRole)) {
        return authArr.some((r) => userRole.indexOf(r) >= 0);
      }

      /*
            Check if user role is string,
            */
      return authArr.includes(userRole);
    }
  }
}

export default AppUtils;

第二:您需要授權組件來處理如下路由:

import React, { Component } from "react";
import AppUtils from "utils/AppUtils";
import { matchRoutes } from "react-router-config";
import { withRouter } from "react-router-dom";
import AppContext from "context/AppContext";

class AppAuthorization extends Component {
  constructor(props, context) {
    super(props);
    const { routes } = context;
    this.state = {
      accessGranted: true,
      routes
    };
  }

  componentDidMount() {
    if (!this.state.accessGranted) {
      this.redirectRoute();
    }
  }

  componentDidUpdate() {
    if (!this.state.accessGranted) {
      this.redirectRoute();
    }
  }

  static getDerivedStateFromProps(props, state) {
    const { location, userRole } = props;
    const { pathname } = location;

    const matched = matchRoutes(state.routes, pathname)[0];

    return {
      accessGranted: matched
        ? AppUtils.hasPermission(matched.route.auth, userRole)
        : true
    };
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextState.accessGranted !== this.state.accessGranted;
  }

  redirectRoute() {
    const { location, userRole, history } = this.props;
    const { pathname, state } = location;
    const redirectUrl = state && state.redirectUrl ? state.redirectUrl : "/";

    /*
        User is guest
        Redirect to Login Page
        */
    if (!userRole || userRole.length === 0) {
      history.push({
        pathname: "/login",
        state: { redirectUrl: pathname }
      });
    } else {
      /*
        User is member
        User must be on unAuthorized page or just logged in
        Redirect to dashboard or redirectUrl
        */
      history.push({
        pathname: redirectUrl
      });
    }
  }

  render() {
    // console.info('App Authorization rendered', accessGranted);
    return this.state.accessGranted ? (
      <React.Fragment>{this.props.children}</React.Fragment>
    ) : null;
  }
}

// AppAuthorization.defaultProps = {
//   userRole: [] // You can manage roles by redux or any state managements
// };

AppAuthorization.contextType = AppContext;

export default withRouter(AppAuthorization);

第三:您需要 authRoles 文件或遠程來管理客戶端上的角色,如下所示:

/**
 * Authorization Roles
 */
const authRoles = {
  admin: ["admin"],
  superAdmin: ["superAdmin"],
  user: ["user"],
  onlyGuest: []
};

export default authRoles;

第四:如果你想繼續這個邏輯,你必須實現你的頁面結構如下:

src
 |---pages
      |---home
           |---HomePage.jsx
           |---HomePageConfig.jsx
      |
      |- The rest of the pages should be implemented in the same way

例如:當你想實現一個只有管理員才能看到的頁面時(管理員主頁配置):

import React from "react";
import authRoles from "auth/authRoles";

export const AdminHomePageConfig = {
  auth: authRoles.admin,
  routes: [
    {
      path: "/admin",
      exact: true,
      component: React.lazy(() => import("./HomePage"))
    }
  ]
};

或者大家都能看到的首頁:

import React from "react";

export const HomePageConfig = {
  routes: [
    {
      path: "/",
      exact: true,
      component: React.lazy(() => import("./HomePage"))
    }
  ]
};

根據上面的示例,您可以在此處輸入帶有roleauth prop ,以限制對頁面的訪問。

為了更深入地了解這個邏輯,我在 Codesandbox 中實現了它,您可以通過以下鏈接查看:

Codesandbox 演示

注意:上面的demo需要更完整,不要把用戶角色存儲在state中,最好使用state管理包(redux,...),也可以通過Z55E7DD3016CE4AC57B9A0F56AF12F進行登錄操作。

您可以創建一個 function 來檢查身份驗證並在進入路由時重定向,而不是創建動態路由。

const yourRouter = () => {
  // yourAuthLogic
  const routeAuth = (Component, props) => {
  // redirect logic
  // here you use the if/else branching based on auth state to redirect  
  // if no redirect
  return (
    <Component {...props} />
  )
}

return (
  <Router>
    <Switch>
      <Route path="/admin" render={() => routeAuth(component, props)} />
      <Route path="/superAdmin" render={() => routeAuth(component, props)} />
   </Switch>
 </Router>
  )
}

問題是 DuynamicRoute 組件在其頂層返回一個 Redirect,但 Redirects 不能直接在 Switch 組件內工作。 這是因為 Switch 中的重定向會導致無限重定向循環。 要解決此問題,您應該從自定義 Route 組件返回頂級 Route,同時處理 Route 標簽之間的重定向邏輯。

另外,值得一提的是,有些路由不應該是特殊保護的路由,而是常規的登陸頁面,例如主頁和登錄頁面。

這是基於您的 CodeSandbox 解決方案的示例項目: https://codesandbox.io/s/vigilant-feather-jbq4j

我這樣做是為了讓 superAdmin 用戶可以訪問管理員級別,但反過來不行。 如果不將活動用戶更改為超級管理員,則較小的管理員無法訪問超級管理員內容。

這是一個對邏輯稍作修改的附加鏈接,用於您希望 admin 和 superAdmin 無法訪問彼此的受保護頁面的用例: https://codesandbox.io/s/brave-haze-zsmn9?文件=/src/ProtectedRoute.js

由於這還沒有一個公認的答案,所以我將提出我用於根據條件添加/刪除路由的簡單方法。

這些示例使用 Typescript 但如果需要,剝離類型應該相對容易。

條件路由組件:

該組件具有所有 Route 道具的完整類型以及一個稱為啟用的附加道具。

當啟用為真時,路由將正常渲染,當為假時,將返回 null。

// ConditionalRoute.tsx
import * as React from 'react';
import { Route, RouteProps } from 'react-router-dom';

interface ConditionalRouteProps extends RouteProps {
    enabled?: boolean;
}

const ConditionalRoute: React.FunctionComponent<ConditionalRouteProps> = ({
    enabled,
    ...routeProps
}) => {
    if (!enabled) {
        return null;
    }

    return (
        <Route {...routeProps} />
    );
};

export default ConditionalRoute;

條件重定向組件:

該組件具有所有 Redirect 道具的完整類型以及一個稱為啟用的附加道具。

如果啟用為真,重定向將正常執行,如果為假,將返回 null。

// ConditionalRedirect.tsx
import * as React from 'react';
import { Redirect, RedirectProps } from 'react-router-dom';

interface ConditionalRedirectProps extends RedirectProps {
    enabled?: boolean;
}

const ConditionalRedirect: React.FunctionComponent<ConditionalRedirectProps> = ({
    enabled,
    ...redirectProps
}) => {
    if (!enabled) {
        return null;
    }

    return (
        <Redirect {...redirectProps} />
    );
};

export default ConditionalRedirect;

使用條件組件:

使用條件路由/重定向,就像使用它們的原始基礎組件一樣,除非啟用屬性為 true,否則它們不會生效。

這也適用於 Switch 組件,因為它將忽略返回 null 的組件。

// App.tsx
import * as React from 'react';
import { BrowserRouter, Switch } from 'react-router-dom';

interface AppProps {
    authenticatedUser?: any;
}

const ConditionalRedirect: React.FunctionComponent<AppProps> = ({
    authenticatedUser
}) => {

    return (
        <BrowserRouter>
            <Switch>
                { 
                    // Always allow the unauthenticated error route
                }
                <Route 
                    path="/error/401" 
                    component={Unauthenticated} 
                />
                { 
                    // If user is authenticated allow member route
                }
                <ConditionalRoute 
                    enabled={!!authenticatedUser} 
                    path="/member" 
                    component={MemberHome} 
                />
                { 
                    // If user is an admin allow admin route
                }
                <ConditionalRoute 
                    enabled={authenticatedUser?.isAdmin} 
                    path="/administration" component={AdminHome} 
                />
                { 
                    // If user is an admin redirect uncaught route 
                    // to administration route
                }
                <ConditionalRedirect 
                    enabled={authenticatedUser?.isAdmin} 
                    path="/" 
                    to="/administration" 
                />
                { 
                    // If user is authenticated redirect uncaught route 
                    // to member route
                }
                <ConditionalRedirect 
                    enabled={!!authenticatedUser} 
                    path="/" 
                    to="/member" 
                />
                { 
                    // If user is not authenticated redirect uncaught 
                    // route to unauthenticated error route 
                }
                <ConditionalRedirect 
                    enabled={!authenticatedUser} 
                    path="/" 
                    to="/error/401" 
                />
            </Switch>
        </BrowserRouter>
    );
};

export default App;

此解決方案的主要警告是,條件中的任何值都必須在渲染任何路線之前准備好進行評估。 例如,如果您發出異步請求以檢查用戶是否在上面的示例應用程序中進行了身份驗證,當用戶在異步請求返回之前最初未定義時,它將重定向到 401 頁面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM