Steuern des Zugriffs auf Seiten mit React Router

Das Problem

Als ich mit React anfing, hatte ich ein Problem. Ich musste den Zugriff auf bestimmte Seiten in einem SPA kontrollieren, das ich mit React und React Router erstellt hatte, und ich konnte keine Bibliotheken finden, die mir dabei helfen könnten, also beschloss ich, ein kleines Dienstprogramm zu schreiben, um mir bei diesem Problem zu helfen. Ich habe es meine React-Router-Middleware genannt. Kitschig, oder?

Ein Beispielszenario

Angenommen, ich habe zwei Ansichten. Login (), Admin-Dashboard () und Super-Admin (). Für die Anmeldung möchte ich, dass nur Benutzer, die derzeit nicht angemeldet sind, diese Seite anzeigen. Administratoren sollten nur von Administratoren und Superadministratoren von Benutzern mit der Rolle Superadministrator gesehen werden.

Angenommen, ich habe meine Routen so eingerichtet:

<Router history={browserHistory} onUpdate={(a) => console.log(a)}>
    <ErrorBoundary>
      <Route exact path="/login" render={() => <Login />} />
      <Route exact path="/admin" render={() => <AdminDashboard />} />
      <Route exact path="/super-admin" render={() => <SuperAdminDashboard />} />
    <ErrorBoundary/>
<Router />

Die Middleware

Mein Middleware-Code sieht so aus

    routeToDisplay (middlewares = [], routeToVisit, directedFrom = '', extra = {}) {
    	const mware = {
        	privateRoute: (routeToVisit, directedFrom) => this.privateRoute(routeToVisit, ),
      		alreadyLoggedIn: (routeToVisit) => this.alreadyLoggedIn(routeToVisit),
            adminAccess: (routeToVisit) => this.adminAccess(routeToVisit),
            superAdminAccess: (routeToVisit, directedFrom) => this.superAdminAccess(routeToVisit, directedFrom),
        }
        let ret = null
       	try{
        	for (let i = 0; i < middlewares.length; i++) {
            	ret = mware[middlewares[i]](routeToVisit, directedFrom, extra)
                if (ret.status === false) {
                	break
                }
            }
            return ret.routeObject
        }catch(e){
        	//handle error here
        }
    }

Verwirrend, oder? Keine Sorge, ich werde es abbauen. Die Funktion routeToDisplay ist das Gehirn hinter der ganzen Middleware-Idee. Die Funktion selbst erwartet drei Argumente

routeToDisplay (middlewares = [], route, directedFrom = '/') {

Middleware: Eine Reihe von Zeichenfolgen, die die Namen der Zugriffsprotokolle darstellen, die ich auf jeder Route implementieren möchte. Zum Beispiel stellt private router Routen dar, denen der Zugriff nicht erlaubt werden sollte, ohne vorher angemeldet zu sein, und schonLoggedIn stellt Routen dar, auf die ich nicht möchte, dass ein Benutzer darauf zugreift, sobald er angemeldet ist. Den Rest können Sie erraten.

routeToVisit: Die Route, die der Benutzer besuchen möchte.

gerichtetVon: Falls die Autorisierung nicht erfolgreich ist, wohin leiten wir den Benutzer weiter. Beispielsweise leiten wir bei privaten Routen den Benutzer zurück zum Login.

Die nächste Zeile enthält eine Liste der verfügbaren Middlewares

const mware = {
        	privateRoute: (routeToVisit, directedFrom) => this.privateRoute(routeToVisit, ),
      		alreadyLoggedIn: (routeToVisit) => this.alreadyLoggedIn(routeToVisit),
            adminAccess: (routeToVisit) => this.adminAccess(routeToVisit),
            superAdminAccess: (routeToVisit, directedFrom) => this.superAdminAccess(routeToVisit, directedFrom),
        }

Im Grunde ist dies nur eine Liste von Middlewares, die der Funktion zugeordnet sind, die das Zugriffsprotokoll auf diese Route implementiert. Die Funktion, der es zugeordnet ist, erledigt einfach die gewünschte Prüfung für uns, zum Beispiel würde privateRoute prüfen, ob der Benutzer angemeldet ist oder nicht, und den Zugriff erlauben oder den Zugriff verweigern.

let ret = null
try{
  for (let i = 0; i < midwares.length; i++) {
    	ret = mware[midwares[i]](routeToVisit, directedFrom, extra)
       		if (ret.status === false) {
            	break
            }
    }
    	return ret.routeObject
    }catch(e){
    	//handle error here
    }

Die obige Funktion durchläuft einfach die Middleware-Namen, die ich übergeben habe, und ruft die ihnen zugeordnete Funktion auf. Die Funktionen geben eine Statuseigenschaft zurück, die wahr ist, wenn der Zugriff erlaubt werden soll, oder falsch, wenn dies nicht der Fall sein sollte.

Da ich eine Reihe von Middlewares erhalte, bedeutet dies, dass ich mehrere Middlewares weitergeben kann. Diese for-Schleife kann sie durchlaufen, und alles ist in Ordnung, solange der Status wahr ist, aber sobald er auf falsch trifft, wird der Zugriff verweigert. Beispielsweise kann ich privateRoute und adminAccess übergeben. Private Route kann true zurückgeben und adminAccess kann false zurückgeben, der Zugriff wird in diesem Fall verweigert.

Die letzte Zeile gib ret.routeObject zurück gibt den Weg zurück, den die Funktion an mich zurückgibt. Die Sache ist, wenn der Zugriff verweigert werden soll, gibt die Funktion eine -Route zurück, die den Benutzer zurück zur Anmeldung oder an einen anderen Ort umleitet. Mal sehen, wie eine oder zwei der Funktionen aussehen.

privateRoute (component, pathname="/") { 
    return (auth.fetchCurrentUser !== null
            ? this._getRouteReturn(true, component)
            : this._getRouteReturn(false,
              <Redirect to={{
                pathname: '/login',
                state: { from: pathname }
              }} />)
    )
  }

Die Funktion übernimmt die Komponente, auf die wir die Route anzeigen möchten, auf die wir umleiten möchten, falls die Autorisierung verweigert wird. Innerhalb der Funktion prüfen wir, ob der aktuelle Benutzer definiert ist oder ob der aktuelle Benutzer angemeldet ist, je nachdem, wie Ihre Authentifizierung aussieht. Wenn der Benutzer ist, rufen wir die Funktion auf

_getRouteReturn()

Passing-Status und die Komponente, die zurückgesendet werden soll. So sieht _getRouteReturn aus

_getRouteReturn (status, routeObject) {
    return {status, routeObject}
  }

Wenn die Autorisierung erfolgreich war, erhalten wir die aktuelle Route zurück, wenn nicht, erhalten wir die Umleitungsroute zurück. In diesem Fall werden wir zurück zum Login umgeleitet. Nachdem die Anmeldung erfolgreich war, werden wir zu der Route weitergeleitet, auf die wir versucht haben zuzugreifen, die uns verweigert wurde. Wenn wir beispielsweise versucht haben, auf das Admin-Dashboard zuzugreifen, ohne angemeldet zu sein, werden wir zur Anmeldung umgeleitet, und sobald die Anmeldung erfolgreich ist, werden wir zum Admin-Dashboard weitergeleitet.

Sie können das Gleiche für die anderen Routen implementieren, zum Beispiel könnte die adminAccess-Route etwa so aussehen.

adminAccess (component, pathname="/") {
//in my case i stored my allowed roles in array form in my db, yours could be different
    if (utils.arrayContains(role, 'admin')) {
      return this._getRouteReturn(true, component)
    }
    return this._getRouteReturn(false,
      <Redirect to={{
        pathname: `${this._account_help}${Constants.userRoles.admin}`
      }} />)
  }

Die obige Methode wie die vorherige nimmt also nur die Komponente, die wir anzeigen möchten. Ich passiere die Route, auf die ich umleiten möchte, nicht, da dies kein Anmeldeproblem ist. Stattdessen übergebe ich einen Pfad zu einer Route, die Informationen darüber anzeigt, was ein Administratorkonto ist, damit der Benutzer weiß, was zu tun ist, um ein Administrator zu werden.

Ich denke, es ist ziemlich einfach.

Verwenden Sie es in unseren Routen

Nun sahen unsere Routen vorher so aus

<Router history={browserHistory} onUpdate={(a) => console.log(a)}>
    <ErrorBoundary>
      <Route exact path="/login" render={() => <Login />} />
      <Route exact path="/admin" render={() => <AdminDashboard />} />
      <Route exact path="/super-admin" render={() => <SuperAdminDashboard />} />
    <ErrorBoundary/>
<Router />

Lassen Sie es uns ein wenig umgestalten. Angenommen, ich habe meine Middleware standardmäßig aus ihrer eigenen Klasse exportiert. Ich werde es früher so importieren

import middleware from './middleware'
<Router history={browserHistory} onUpdate={(a) => console.log(a)}>
    <ErrorBoundary>
      <Route exact path="/login" 
      	render={() => middleware.routeDisplay(['alreadyLoggedIn'],<Login />)
      } />
      <Route exact path="/admin" 
        render={() => middleware.routeDisplay(['privateRoute','adminAccess'],<AdminDashboard />)} />
      <Route exact path="/super-admin" 
      	render={() => middleware.routeDisplay(['privateRoute','superAdminAccess'],               <SuperAdminDashboard />)
        } />
    <ErrorBoundary/>
<Router />

Und das ist es. Sehen wir uns unten den Code für die gesamte Middleware an.

import React from 'react'
import {
    Redirect
} from 'react-router-dom'
import auth from './stores/authenticationStore'
import utils from './stores/utils'

class Middleware {
  routeToDisplay (middlewares = [], routeToVisit, directedFrom = '', extra = {}) {
    	const mware = {
        	privateRoute: (routeToVisit, directedFrom) => this.privateRoute(routeToVisit, ),
      		alreadyLoggedIn: (routeToVisit) => this.alreadyLoggedIn(routeToVisit),
            adminAccess: (routeToVisit) => this.adminAccess(routeToVisit),
            superAdminAccess: (routeToVisit, directedFrom) => this.superAdminAccess(routeToVisit, directedFrom),
        }
        let ret = null
       	try{
        	for (let i = 0; i < middlewares.length; i++) {
            	ret = mware[middlewares[i]](routeToVisit, directedFrom, extra)
                if (ret.status === false) {
                	break
                }
            }
            return ret.routeObject
        }catch(e){
        	//handle error here
        }
    }
    
    _getRouteReturn (status, routeObject) {
      return {status, routeObject}
    }
    
    adminAccess (component, pathname="/") {
    //in my case i stored my allowed roles in array form in my db, yours could be       different
        if (utils.arrayContains(role, 'admin')) {
          return this._getRouteReturn(true, component)
        }
        return this._getRouteReturn(false,
          <Redirect to={{
            pathname: `${this._account_help}${Constants.userRoles.admin}`
          }} />)
      }
      
      privateRoute (component, pathname="/") { 
        return (auth.fetchCurrentUser !== null
                ? this._getRouteReturn(true, component)
                : this._getRouteReturn(false,
                  <Redirect to={{
                    pathname: '/login',
                    state: { from: pathname }
                  }} />)
        )
      }
}

Similar Posts

Leave a Reply

Your email address will not be published.