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

Posted

技术标签:

【中文标题】React Router 用户角色的最佳实践 (Firebase)【英文标题】:Best practice for React Router user roles (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 的新手,仍然有点害怕处理状态和重要数据,例如用户角色属性。

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

谢谢。

【问题讨论】:

遇到此问题的任何人都可能对这个long read React + React Router + Firebase tutorial 感兴趣,它会引导您通过角色进行身份验证和授权。 【参考方案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 以确保您的数据库安全!

让我知道它是否有效

【讨论】:

以上是关于React Router 用户角色的最佳实践 (Firebase)的主要内容,如果未能解决你的问题,请参考以下文章

将登录用户的角色存储在 vuex 安全/最佳实践中吗?

最佳用户角色权限数据库设计实践? [关闭]

最佳用户角色权限数据库设计实践? [关闭]

Keycloak 授权 - 最佳实践角色与组

具有两个角色的帐户之间的关系的最佳实践是啥?

限制服务帐户可以配置的角色和资源的最佳实践