React Router用户角色的最佳实践(Firebase) [英] Best practice for React Router user roles (Firebase)

查看:58
本文介绍了React Router用户角色的最佳实践(Firebase)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序将具有2个角色,即Employee和Admin. 我正在尝试实现中间件,以便在用户无权查看内容的情况下重定向用户.在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的新手,但仍然害怕使用状态和重要数据(例如用户角色属性).

在实现用户角色方面,我还需要真正注意哪些其他方面?

谢谢.

解决方案

让用户角色正常工作!每个项目都有其特定性,但是我将按照以下方式进行操作:

在首次渲染应用程序之前,必须确保已加载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规则,以确保数据库安全! /p>

让我知道它是否有效

My application will have 2 roles, Employee and Admin. I'm trying to implement middleware so users get redirected if they are not authorized to see the content. Is handling not just general authentication but also user roles in React Router good practice?

My first thought was to add a custom role attribute to firebase.auth().currentUser, but adding attributes to currentUser is not allowed by firebase.

If so, how would I do it? Through state or fetching it from my Firebase DB like this?:

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>

I'm new to React and Redux and still a bit scared of working with state and important data such as the user role attribute.

What are some other areas I need to be really careful with concerning the implementation of user roles?

Thanks.

解决方案

lets get that user roles working! Every project has its specificities, but here's how I would do it:

Before you first render your app, you've got to be sure that firebase user/currentUser/currentAuth has loaded. If you have roles, just make sure to fetch it it the user is logged in.

Here's an example:

On 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);

and then on 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();
    }
  });
};

All right!!! We have all we need in our store. So now we just have to check that on our onEnter functions of our app:

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>);
};

Theres probably tons of problems on this code, but I believe you can understand the principles. Basically you should pre-fetch the role so you don't have to do it on every route change.

One other tip I can give you is that if you'll have tons of employees and just a handful of admins, just save the admins. This way you'll only have like 20 entries on your roles object instead of hundreds of thousands. That tiny || 'employees' can save you lots of space.

Keep in mind that you can just as easily add more roles if you need. Also, this example uses Redux, but you don't have to.

!!! IMPORTANT !!!

All of this will only keep people from accessing the pages, but smartypants can use the console or a rest client to try to stick their noses in parts of your database where they shouldn't! Be sure to understand and make good use of firebase rules to keep your database secure!

Let me know if it worked

这篇关于React Router用户角色的最佳实践(Firebase)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆