React Router用户角色的最佳做法(Firebase)

时间:2016-07-13 16:05:53

标签: reactjs firebase redux react-router firebase-authentication

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

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

如果是这样,我该怎么做? 通过状态或从我的Firebase DB中获取这样的内容?:

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 个答案:

答案 0 :(得分:4)

让这些用户角色有效!每个项目都有其特殊性,但这就是我要做的事情:

在首次呈现应用之前,您必须确保已加载firebase用户/ 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 rules来确保数据库的安全!

让我知道它是否有效