reactjs - React Router v5.1.2 公共(public)和 protected 经过身份验证和基于角色的路由

标签 reactjs authentication keycloak react-router-dom role-based-access-control

目标是让/login 作为唯一的公共(public)路由,一旦登录,用户就拥有基于用户角色的路由。 身份验证是使用 Keycloak 完成的,我从 keycloak.idTokenParsed.preferred_username 获取用户:管理员、经理、工程师、运算符(operator)。 如果运算符(operator)尝试进入角色,受限路线将被重定向到/notauthorized 页面。 (这部分没做) 如果未登录,用户将被重定向到/login 页面。 (这部分已完成/有效)

有更好的方法吗?不重复路由并在 Routes.jsx 中添加其他用户有点困惑。 如何实现角色限制重定向到/notauthorized?

App.js(没有所有导入,并且缺少带有mapStateToProps、mapDispatchToProps和导出默认App的底部部分)

import React, { useEffect } from "react";
import { Route, Redirect, Switch } from "react-router-dom"

let routeWithRole = [];
let user = '';

const AppContainer = ({ keycloak }) => {
  if(keycloak && keycloak.token) {
    user = keycloak.idTokenParsed.preferred_username
    if( user === 'admin') {
      routeWithRole = admin;
    } else if( user === 'engineer') {
      routeWithRole = engineer
    } else if(user === 'manager') {
      routeWithRole = manager
    } else {
      routeWithRole = operator
    }
  }

   return (
    <div>
          {(keycloak && keycloak.token) ?
            <React.Fragment>
                <Switch>

                  {routeWithRole.map((prop, key) => {
                    console.log('App.js Prop & Key ', prop, key)
                    return (
                      <Route
                        path={prop.path}
                        key={key}
                        exact={true}
                        component={prop.component}
                      />
                    );
                  })}
                  <Redirect from={'/'} to={'/dashboard'} key={'Dashboard'} />
                </Switch>
            </React.Fragment>
            :
            <React.Fragment>
              <Switch>
                {publicRoutes.map((prop, key) => {
                  return (
                    <Route
                      path={prop.path}
                      key={key}
                      exact={true}
                      component={(props) =>
                        <prop.component
                          keycloak={keycloak}
                          key={key} {...props} />
                      }
                    />
                  );
                })}
                <Redirect from={'/'} to={'/login'} key={'login'} />
              </Switch>
            </React.Fragment>
          }
      </div>
  )
}

Routes.jsx(缺少所有导入)

export const publicRoutes = [
  { path: "/login", type: "public", name: "landing page", component: LandingPageContainer },
]

export const admin = [
  { path: "/createUser", name: "Create User", component: CreateUser},
  { path: "/editUser", name: "Edit User", component: EditUser},
  { path: "/createdashboard", name: "Create Dashboard", component: CreateDashboard },
  { path: "/editashboard", name: "Edit Dashboard", component: EditDashboard },
  { path: "/createcalendar", name: "Create Calendar", component: CreateCalendar },
  { path: "/editcalendar", name: "list of factories", component: EditCalendar },
  { path: "/dashboard", name: "Dashboard", component: Dashboard }
]

export const engineer = [
  { path: "/createdashboard", name: "Create Dashboard", component: CreateDashboard },
  { path: "/editashboard", name: "Edit Dashboard", component: EditDashboard },
  { path: "/dashboard", name: "Dashboard", component: Dashboard },
  { path: "/notauthorized", name: "Not Authorized", component: Notauthorized }
]

export const manager = [
  { path: "/createcalendar", name: "Create Calendar", component: CreateCalendar },
  { path: "/editcalendar", name: "Edit Calendar", component: EditCalendar },
  { path: "/dashboard", name: "Dashboard", component: Dashboard },
  { path: "/notauthorized", name: "Not Authorized", component: Notauthorized }
]

export const operator = [
  { path: "/dashboard", name: "Dashboard", component: Dashboard },
  { path: "/notauthorized", name: "Not Authorized", component: Notauthorized }
]

最佳答案

当我们在 react 初始化之前知道“keycloak”(不是“keycloak”的异步加载数据)时,我会考虑该选项。如果你理解这个想法,你将能够改进

主要思想是显示所有路由,但几乎所有路由都将是 protected 路由。请参阅示例:

render (
  <Switch>
    <Route exact path="/login"> // public route
      <LandingPageContainer />
    </Route>
    <AuthRoute exact path="/dashboard"> // for any authorized user
      <Dashboard />
    </AuthRoute>
    <AdminRoute path="/create-user"> // only for admin route
      <CreateUser />
    </AdminRoute>
    <AdminOrEngineerRoute path="/create-dashboard"> // only for admin or engineer route
      <CreateDashboard />
    </AdminOrEngineerRoute>
    <Redirect to="/dashboard" /> // if not matched any route go to dashboard and if user not authorized dashboard will redirect to login
  </Switch>
);

然后您可以创建如下组件列表:

const AVAILABLED_ROLES = ['admin', 'engineer'];

const AdminOrEngineerRoute = ({ children, ...rest }) {
  const role = keycloak && keycloak.token ? keycloak.idTokenParsed.preferred_username : '';

  return (
    <Route
      {...rest}
      render={({ location }) =>
        AVAILABLED_ROLES.includes(role) && ? (
          children
        ) : (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: location }
            }}
          />
        )
      }
    />
  );
}

因此 AdminOrEngineerRoute 将只允许管理员或工程师传递到此路由,否则您将获得/登录页面

永远是你的“瘀伤”

关于reactjs - React Router v5.1.2 公共(public)和 protected 经过身份验证和基于角色的路由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61131446/

相关文章:

javascript - Action 必须是普通对象。尝试将 Action 分派(dispatch)为 redux 形式

javascript - react : get child component data from parent

reactjs - 在 React-Day-Picker 中禁用所有 future 的日子?

.htaccess - htaccess 身份验证 rest api 方法

spring - GWT Spring 安全集成(纯 GWT,无 JSP)

kubernetes - 使用 codecentrics Helm Charts 在 Kubernetes 高可用性集群(使用 ldap 作为用户联合)上的 Keycloak

javascript - Reactjs使用状态: select onChange triggers setState but component doesn't re-render

database - 有数据库的 Authboss

spring-boot - Spring Boot 应用程序中的 keycloak.json 文件

Azure Ad 作为 keycloak 中的 OIDC 身份提供程序,但随机 UUId 作为 IDP "userid"添加,无法与现有用户同步