React Router 用户角色的最佳实践 (Firebase)

IT技术 reactjs firebase redux react-router firebase-authentication
2021-05-19 00:58:14

我的应用程序将有 2 个角色,员工和管理员。我正在尝试实现中间件,以便用户在未被授权查看内容时被重定向。在 React Router 中不仅处理一般身份验证而且处理用户角色是好的做法吗?

我的第一个想法是向 firebase.auth().currentUser 添加自定义角色属性,但 firebase 不允许向 currentUser 添加属性。

如果是这样,我该怎么做?通过状态或像这样从我的 Firebase 数据库中获取它?:

var requireEmp = (nextState, replace, next) => {
 var role;
 var uid = firebase.auth().currentUser.uid;
 firebase.database().ref('/users/' + uid + '/role').once('value').then((user) => {
  role = user.val().role;
 });
 if (role !== 'employee') {
  replace('/');     
 }
 next();
};

...

<Router history={hashHistory}>
 <Route path="/" >
  <Route path="home" component={Main} onEnter={requireLogin}>
    <Route path="work" component={Work} onEnter={requireEmp}/>
    <Route path="profile" component={Profile} />
    <IndexRoute component={Profile}/>
  </Route>
 </Route>
</Router>

我是 React 和 Redux 的新手,仍然有点害怕处理状态和重要数据,例如用户角色属性。

关于用户角色的实现,还有哪些其他方面我需要非常小心?

谢谢。

1个回答

让用户角色正常工作!每个项目都有其特殊性,但我会这样做:

在您首次呈现您的应用程序之前,您必须确保 firebase user/currentUser/currentAuth 已加载。如果您有角色,只需确保在用户登录时获取它。

下面是一个例子:

在 index.jsx 上:

import { initializeApp } from './myFirebase';

const routes = routesConfig(store);

let appHasRendered = false;

const renderAppOnce = () => {
  if (appHasRendered) return;

  render(
    <Provider store={store}>
      <Router history={syncedHistory} routes={routes} />
    </Provider>,
    document.getElementById('app')
  );

  appHasRendered = true;
};

initializeApp(renderAppOnce, store.dispatch);

然后在 myFirebase.js 上:

export const initializeApp = (renderAppOnce, dispatch) => {
  firebaseAuth.onAuthStateChanged((user) => {

    if (user) {
      // We have a user, lets send him and his role to the store

      firebaseRef.child('users/roles').once('value', (snap) => {
        dispatch(authLoggedIn({ 
          ...user.toJSON(), 
          role: snap.val() || 'employee'
        }));
        renderAppOnce();
      });

    } else {
      // There's no user, let's move on
      dispatch(authLoggedOut());
      renderAppOnce();
    }
  });
};

好的!!!我们店里有我们需要的一切。所以现在我们只需要检查我们应用程序的 onEnter 函数:

const routesConfig = (store) => {
  // Confirms user is not authenticated
  const confirmNoAuth = (nextState, replace) => {
    if (store.getState().user) {
      replace({ pathname: '/', state: { nextPathname: nextState.location.pathname } });
    }
  };

  // Confirms user is authenticated
  const confirmAuth = (nextState, replace) => {
    if (!store.getState().user) {
      replace({ pathname: '/', state: { nextPathname: nextState.location.pathname } });
    }
  };

  // Confirms user has a specific role
  const confirmRole = role => ((nextState, replace) => {
    if (store.getState().user.role !== role) {
      replace({ pathname: '/', state: { nextPathname: nextState.location.pathname } });
    }
  });

  return (<Route path="/">
    <IndexRoute component={HomePage} />
    <Route path="login" component={LoginPage} onEnter={confirmNoAuth} />
    <Route path="dasboard" component={DashboardPage} onEnter={confirmAuth} />
    <Route path="adminsonly" component={AdminDashboardPage} onEnter={confirmRole('admin')} />
  </Route>);
};

这段代码可能有很多问题,但我相信你能理解其中的原理。基本上你应该预取角色,这样你就不必在每次路由更改时都这样做。

我可以给你的另一个提示是,如果你有大量的员工和少数管理员,只需保存管理员。这样,您的角色对象上将只有 20 个条目,而不是数十万个条目。那个小小的|| 'employees'可以为你节省很多空间。

请记住,您可以根据需要轻松添加更多角色。此外,此示例使用 Redux,但您不必这样做。

!!!重要的 !!!

所有这些只会阻止人们访问页面,但是聪明人可以使用控制台或休息客户端来尝试将他们的鼻子伸入数据库中他们不应该访问的部分!请务必了解并充分利用firebase 规则来确保您的数据库安全!

让我知道它是否有效