2017-03-02 30 views
7

我正在React和Redux(帶有Node.js後端)中編寫單頁應用程序。根據用戶角色隱藏一些React組件子代

我想實現基於角色的訪問控制,並希望控制應用程序的某些部分(或子部分)的顯示。

我要得到的Node.js,這僅僅是這樣的結構的對象權限列表:

{ 
    users: 'read', 
    models: 'write', 
    ... 
    dictionaries: 'none', 
} 

是受保護的資源,

是用戶權限對於此資源(以下之一:none,read,write)。

我正在將它存儲到redux狀態。看起來很簡單。

none權限將被react-router路由onEnter/onChange掛鉤或redux-auth-wrapper檢查。這似乎也很容易。

但是,對任何組件視圖應用read/write權限(例如,如果用戶具有{ models: 'read' }權限,請隱藏Models組件中的編輯按鈕)的最佳方式是什麼。

我發現this solution和改變它有點爲我的任務:

class Check extends React.Component { 
    static propTypes = { 
    resource: React.PropTypes.string.isRequired, 
    permission: React.PropTypes.oneOf(['read', 'write']), 
    userPermissions: React.PropTypes.object, 
    }; 

    // Checks that user permission for resource is the same or greater than required 
    allowed() { 
    const permissions = ['read', 'write']; 
    const { permission, userPermissions } = this.props; 
    const userPermission = userPermissions[resource] || 'none'; 

    return permissions.indexOf(userPermission) >= permissions.indexOf(permission) 
    } 

    render() { 
    if (this.allowed()) return { this.props.children }; 
    } 
} 

export default connect(userPermissionsSelector)(Check) 

其中userPermissionsSelector會是這樣的:(store) => store.userPermisisons並返回用戶權限的對象。

然後包裹保護的元素與Check

<Check resource="models" permission="write"> 
    <Button>Edit model</Button> 
</Check> 

因此,如果用戶沒有write權限models按鈕不會顯示。

有沒有人做過類似的事情?有沒有比這更「優雅」的解決方案?

謝謝!

P.S.當然用戶權限也會在服務器端進行檢查。

+0

我以前做過這樣的事情。我有一個基於用戶限制的管理頁面。你在做什麼基本上是我做的。我使用php作爲後端,並通過檢查PHP會話來驗證它(不是最好的,但是與我所瞭解/知道的一起工作)。它成功隱藏了頁面。如果你的解決方案正在工作,那麼我不會過多地關注它,儘管你可能想在渲染中使用'else'語句來返回類似'你無法訪問這個頁面'的東西,這樣用戶可以看到一些東西,而不是認爲頁面已損壞 –

+0

謝謝,但在這種情況下'else'語句不是必需的,因爲我想在已打開的頁面中隱藏一些操作控件​​,例如「編輯」或「刪除」按鈕。 –

+0

這很好,如果你喜歡'{exists &&

some stuff
}'並且存在是falsey,那麼div將不存在(不僅僅是display:none') –

回答

2

嗯,我想我明白你想要什麼。我做了一些對我有用的事情,我喜歡我的方式,但我知道其他可行的解決方案都在那裏。

我寫的是一個HOC react-router風格。

基本上我有我的PermissionsProvider其中我初始化用戶權限。我有另一個與Permissions HOC注入我以前提供給我的組件的權限。

因此,如果我需要檢查特定組件中的權限,我可以輕鬆訪問它們。

// PermissionsProvider.js 
import React, { Component } from "react"; 
import PropTypes from "prop-types"; 
import hoistStatics from "hoist-non-react-statics"; 

class PermissionsProvider extends React.Component { 
    static propTypes = { 
    permissions: PropTypes.array.isRequired, 
    }; 

    static contextTypes = { 
    permissions: PropTypes.array, 
    }; 

    static childContextTypes = { 
    permissions: PropTypes.array.isRequired, 
    }; 

    getChildContext() { 
    // maybe you want to transform the permissions somehow 
    // maybe run them through some helpers. situational stuff 
    // otherwise just return the object with the props.permissions 
    // const permissions = doSomething(this.props.permissions); 
    // maybe add some validation methods 
    return { permissions: this.props.permissions }; 
    } 

    render() { 
    return React.Children.only(this.props.children); 
    } 
} 

const withPermissions = Component => { 
    const C = (props, context) => { 
    const { wrappedComponentRef, ...remainingProps } = props; 

    return (
     <Component permissions={context.permissions} {...remainingProps} ref={wrappedComponentRef} /> 
    ); 
    }; 

    C.displayName = `withPermissions(${Component.displayName || Component.name})`; 
    C.WrappedComponent = Component; 
    C.propTypes = { 
    wrappedComponentRef: PropTypes.func 
    }; 

    C.contextTypes = { 
    permissions: PropTypes.array.isRequired 
    }; 

    return hoistStatics(C, Component); 
}; 

export { PermissionsProvider as default, withPermissions }; 

好吧我知道這是很多代碼。但這些都是HOC(你可以學到更多here)。

高階組件(HOC)是React中的一項高級技巧,用於重用組件邏輯的 。 HOC本身不是React API的一部分。 它們是從React的構圖本質中浮現出來的一種模式。 具體而言,高階組件是一個函數,它接收一個組件並返回一個新組件。

基本上我這樣做是因爲我受到了路由器的反應。 每當你想知道一些路由的東西,你可以添加裝飾@withRouter,他們將道具注入你的組件。 那麼爲什麼不做同樣的事情呢?

  1. 首先必須建立與供應商的權限
  2. 然後使用withPermissions裝飾上檢查權限

//App render 
return (
    <PermissionsProvider permissions={permissions}> 
     <SomeStuff /> 
    </PermissionsProvider> 
); 

某處內SomeStuff組件你有一個廣泛傳播的工具欄,檢查權限?

@withPermissions 
export default class Toolbar extends React.Component { 
    render() { 
    const { permissions } = this.props; 

    return permissions.canDoStuff ? <RenderStuff /> : <HeCantDoStuff />; 
    } 
} 

如果您不能使用裝飾導出工具欄這樣

export default withPermissions(Toolbar); 

這裏是一個codesandbox,我在實踐中顯示了它:

https://codesandbox.io/s/lxor8v3pkz

注:

  • 我真的真的簡化了權限,因爲這個邏輯來自你的最終目的,並且爲了演示目的,我簡化了它們。
  • 我認爲權限是一個數組,所以這就是爲什麼我檢查HOC中的PropTypes.array
  • 這是一個非常漫長而複雜的答案,我嘗試用我最好的能力來表達。請不要在這裏和那裏燒我一些錯誤:)
+0

@AntonNovik你對此有何看法? – Lokuzt