2017-03-02 2 views
7

Ich schreibe eine einzelne Seite Anwendung in React und Redux (mit einem Node.js Backend).Einige React-Komponenten-Children je nach Benutzerrolle ausblenden

Ich möchte rollenbasierte Zugriffskontrolle implementieren und die Anzeige bestimmter Teile (oder Unterteile) der App steuern.

Ich werde von Node.js Berechtigungsliste erhalten, die mit einer solchen Struktur nur ein Objekt ist:

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

Schlüssel ist Ressource geschützt,

Wert ist die Benutzerberechtigung für diese Ressource (eines von: none, read, write).

Ich speichere es im Redux-Zustand. Scheint einfach genug.

none Die Erlaubnis wird von react-router Routen onEnter/onChange Haken oder überprüft werden. Es scheint auch einfach zu sein.

Aber was ist der beste Weg, um read/write Berechtigungen auf alle Komponentenansicht anwenden (z. B. ausblenden Bearbeitungsschaltfläche in der Modellkomponente, wenn der Benutzer { models: 'read' } Erlaubnis hat).

habe ich this solution und ändern Sie es ein bisschen für meine Aufgabe gefunden:

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) 

wo userPermissionsSelector wäre so etwas wie dieses: (store) => store.userPermisisons und gibt Objekt Benutzerberechtigung.

wickeln Dann geschützten Element mit Check:

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

so, wenn der Benutzer nicht write Berechtigung verfügt, für models die Schaltfläche wird nicht angezeigt.

Hat jemand so etwas getan? Gibt es mehr "elegante" Lösung als das?

danke!

P.S. Natürlich wird die Benutzerberechtigung auch auf der Serverseite überprüft.

+0

Ich habe so etwas schon einmal gemacht. Ich hatte eine Admin-Seite, die basierend auf dem Benutzer eingeschränkt wurde. Was Sie tun, ist im Grunde, was ich getan habe. Ich benutzte PHP als mein Backend und validierte es durch Überprüfung der PHP-Sitzung (nicht die beste, aber arbeitete mit dem, was ich hatte/wusste). Und es hat die Seite erfolgreich versteckt. Wenn Ihre Lösung funktioniert, würde ich nicht zu viel darüber streiten, obwohl Sie eine 'else'-Anweisung im Rendering haben möchten, nur um etwas wie' Sie haben keinen Zugriff auf diese Seite 'oder etwas, nur so Benutzer zurückzugeben kann etwas sehen, anstatt zu denken, die Seite ist gebrochen –

+0

Vielen Dank, aber "else" Anweisung in diesem Fall ist nicht erforderlich, weil ich einige Aktionssteuerungen wie "Bearbeiten" oder "Löschen" -Schaltflächen in bereits geöffneten Seite ausblenden möchten. –

+0

das ist in Ordnung, wenn Sie etwas tun wie '{exists &&

some stuff
}' und exists ist falsch, dann wird das div nicht existieren (nicht nur 'display: none') –

Antwort

2

Nun, ich glaube, ich habe verstanden, was Sie wollen. Ich habe etwas gemacht, das für mich funktioniert und ich mag die Art, wie ich es habe, aber ich verstehe, dass andere brauchbare Lösungen da draußen sind.

Was ich schrieb, war ein HOC-React-Router-Stil.

Grundsätzlich habe ich meine PermissionsProvider, wo ich die Benutzer Berechtigungen init. Ich habe eine andere mit Permissions HOC, die die Berechtigungen, die ich früher in meiner Komponente zur Verfügung gestellt injiziert.

Also wenn ich jemals Berechtigungen in dieser spezifischen Komponente überprüfen muss, kann ich leicht auf sie zugreifen.

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

Ok Ich weiß, das ist eine Menge Code. Aber das sind HOC (Sie können mehr lernen here).

Ein höherer Ordnung Komponente (HOC) ist eine fortgeschrittene Technik in React für Komponentenlogik wiederzuverwenden. HOCs sind nicht Teil der React API an sich. Sie sind ein Muster, das aus der kompositorischen Natur von React hervorgeht. Konkret ist eine Komponente höherer Ordnung eine Funktion, die eine Komponente übernimmt und eine neue Komponente zurückgibt.

Grundsätzlich habe ich das getan, weil ich inspiriert wurde, was reaction-router tat. Wann immer Sie etwas Routing-Zeug wissen möchten, können Sie einfach den Dekorateur @withRouter hinzufügen und sie Requisiten in Ihre Komponente injizieren. Warum also nicht dasselbe tun?

  1. Zuerst müssen Sie Setup die Berechtigungen mit dem Provider
  2. Dann nutzen Sie die withPermissions Dekorateur auf die Komponenten, die Berechtigungen prüfen

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

Irgendwo in SomeStuff Sie haben eine weit verbreitete Toolbar, die Berechtigungen prüft?

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

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

Wenn Sie Dekorateure nicht verwenden Sie die Toolbar exportieren wie diese

export default withPermissions(Toolbar); 

ist hier ein codesandbox, wo ich es in der Praxis zeigte:

https://codesandbox.io/s/lxor8v3pkz

NOTES:

  • Ich habe die Berechtigungen wirklich sehr vereinfacht, weil diese Logik von deinem Ende kommt und zu Demozwecken habe ich sie vereinfacht.
  • Ich nahm die Berechtigungen ein Array waren damit ist, warum ich die PropTypes.array in dem HOV überprüfen
  • Es ist eine wirklich lange und komplizierte Antwort, und ich versuchte meine Beste Fähigkeit zu artikulieren. Bitte grill mich nicht für einige Fehler hier und da :)
+0

@AntonNovik Was ist deine Situation damit? – Lokuzt

Verwandte Themen