【问题标题】:Best practice for React Router user roles (Firebase)React Router 用户角色的最佳实践 (Firebase)
【发布时间】:2016-11-16 08:04:41
【问题描述】:

我的应用程序将有 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 的新手,仍然有点害怕处理状态和重要数据,例如用户角色属性。

关于用户角色的实现,我还需要注意哪些其他方面?

谢谢。

【问题讨论】:

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


【解决方案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,但您不必这样做。

!!!重要!!!

所有这些只会阻止人们访问这些页面,但是 smartypants 可以使用控制台或休息客户端尝试在不应该访问的数据库部分中窥探!请务必了解并善用firebase rules 以确保您的数据库安全!

让我知道它是否有效

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-02
    • 2017-02-04
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 2018-04-19
    • 1970-01-01
    • 2017-05-20
    相关资源
    最近更新 更多