7

Sto creando un'app Web che soddisferà due requisiti per gli utenti. Nota: sono nuovo di AngularJS come piattaforma di sviluppo web.Come gestire l'autorizzazione basata sui ruoli in AngularJS?

Front-end - 1: è una funzionalità di ricerca in cui gli utenti possono cercare documenti e studi specifici in base alla ricerca di parole chiave e ai filtri. Questo è stato implementato usando MySQL per il recupero dei dati e la visualizzazione usando AngularJS.

Front-end - 2: gli utenti avranno la possibilità di creare un account nell'app Web. Scopo dell'account è:

  1. Salvare le query di ricerca.
  2. Se l'amministratore associa ciascun utente a un ruolo specifico, gli utenti avranno accesso a opzioni extra quali la modifica dei documenti presenti nel database e il caricamento di nuovi documenti e host di altre pagine.

La mia domanda:

come gestire l'autorizzazione in base ruolo nella AngularJS? Io non sono in grado di capire come creare un quadro che coinvolge seguenti funzionalità: - Gli utenti ottengono un ruolo associato a loro - Impedire agli utenti di accedere pagine o funzionalità che non sono associati a quei ruoli

Ho letto su su pochi articoli SO così come tutorial, ma ogni tutorial termina con l'autore dicendo che l'autorizzazione basata sui ruoli dovrebbe essere gestita sul lato server e capisco perché questo è vero.

Sarebbe bello se qualcuno potesse indicarmi esercitazioni o revisioni che hanno l'autorizzazione basata sui ruoli implementata sul lato server per AngularJS.

Grazie!

risposta

10

Uso l'autorizzazione basata sui ruoli sul backend e sul frontend. Dal momento che sto usando UI-router per il routing, la miglior risorsa che ho trovato (e migliorato per le mie esigenze) è questo articolo:

collegamento scaduto

Se si utilizza interfaccia utente del router, sicuramente check it out. Fondamentalmente è necessario impostare la sicurezza dei percorsi e intercettare tutte le modifiche del percorso. L'articolo include anche una direttiva per nascondere gli elementi dell'interfaccia utente, se l'utente non ha il permesso di accedere al contenuto dietro di esso.


Edit: Aggiunta di un codice.

In primo luogo, è necessario che le autorizzazioni dell'utente siano memorizzate da qualche parte, ad es.sul oggetto utente serializzato in localStorage:

{"id":1,"name":"user","created_at":"2016-04-17 18:58:19","gender":"m","roles":["admin"]} 

Poi, ci sono due parti importanti:

  • direttiva - per determinare se l'elemento deve essere visibile o meno sulla base di autorizzazione assegnato
  • servizi - per gestire il controllo delle autorizzazioni

direttiva:

(function() { 
    'use strict'; 

    angular 
    .module('app') 
    .directive('access', access); 

    /** @ngInject */ 
    function access(authorization) { 
    var directive = { 
     restrict: 'A', 
     link: linkFunc, 
    }; 

    return directive; 

    /** @ngInject */ 
    function linkFunc($scope, $element, $attrs) { 
     var makeVisible = function() { 
     $element.removeClass('hidden'); 
     }; 

     var makeHidden = function() { 
     $element.addClass('hidden'); 
     }; 

     var determineVisibility = function (resetFirst) { 
     var result; 

     if (resetFirst) { 
      makeVisible(); 
     } 

     result = authorization.authorize(true, roles, $attrs.accessPermissionType); 

     if (result === authorization.constants.authorised) { 
      makeVisible(); 
     } else { 
      makeHidden(); 
     } 
     }; 

     var roles = $attrs.access.split(','); 

     if (roles.length > 0) { 
      determineVisibility(true); 
     } 
    } 
    } 

})(); 

È necessario impostare il CSS in modo che gli elementi con classe hidden non siano visibili.

Servizio:

(function() { 
    'use strict'; 

    angular 
    .module('app') 
    .factory('authorization', authorization); 

    /** @ngInject */ 
    function authorization($rootScope) { 
    var service = { 
     authorize: authorize, 
     constants: { 
     authorised: 0, 
     loginRequired: 1, 
     notAuthorised: 2 
     } 
    }; 

    return service; 

    function authorize(loginRequired, requiredPermissions, permissionCheckType) { 
     var result = service.constants.authorised, 
      user = $rootScope.currentUser, 
      loweredPermissions = [], 
      hasPermission = true, 
      permission; 

     permissionCheckType = permissionCheckType || 'atLeastOne'; 

     if (loginRequired === true && user === undefined) { 
      result = service.constants.loginRequired; 

     } else if ((loginRequired === true && user !== undefined) && 
        (requiredPermissions === undefined || requiredPermissions.length === 0)) { 
      result = service.constants.authorised; 

     } else if (requiredPermissions) { 

      loweredPermissions = []; 

      angular.forEach(user.roles, function (permission) { 
       loweredPermissions.push(permission.toLowerCase()); 
      }); 

      for (var i = 0; i < requiredPermissions.length; i += 1) { 
       permission = requiredPermissions[i].toLowerCase(); 

       if (permissionCheckType === 'combinationRequired') { 
        hasPermission = hasPermission && loweredPermissions.indexOf(permission) > -1; 
        // if all the permissions are required and hasPermission is false there is no point carrying on 
        if (hasPermission === false) { 
         break; 
        } 
       } else if (permissionCheckType === 'atLeastOne') { 
        hasPermission = loweredPermissions.indexOf(permission) > -1; 
        // if we only need one of the permissions and we have it there is no point carrying on 
        if (hasPermission) { 
         break; 
        } 
       } 
      } 

      result = hasPermission ? 
        service.constants.authorised : 
        service.constants.notAuthorised; 
     } 

     return result; 
    } 
    } 
})(); 

Ora, è possibile utilizzare la direttiva per mostrare/nascondere elemento:

<a ui-sref="app.administration" class="btn btn-primary pull-right" access="admin">Administration</a> 

Naturalmente questo nasconde solo l'elemento di DOM, quindi è necessario fare il controllo dell'autorizzazione anche sul server.

Questa prima parte ha risolto la visualizzazione/occultamento degli elementi nell'interfaccia utente, ma è anche possibile proteggere i percorsi delle app.

definizione della rotta:

(function() { 
    'use strict'; 

    angular 
    .module('app') 
    .config(routeConfig); 

    /** @ngInject */ 
    function routeConfig($stateProvider) { 
    $stateProvider 
     .state('app.dashboard', { 
     url: '/dashboard', 
     data: { 
      access: { 
      loginRequired: true 
      } 
     }, 
     templateUrl: 'template_path', 
     controller: 'DashboardController as vm' 
     } 
    } 
})(); 

e ora basta controllare il permesso in $stateChangeStart evento

(function() { 
    'use strict'; 

    angular 
    .module('app') 
    .run(runBlock); 

    /** @ngInject */ 
    function runBlock($rootScope, $state, authorization) { 
    $rootScope.$on('$stateChangeStart', function(event, toState) { 
     // route authorization check 
     if (toState.data !== undefined && toState.data.access !== undefined) { 
     authorised = authorization.authorize(toState.data.access.loginRequired, 
              toState.data.access.requiredPermissions, 
              toState.data.access.permissionCheckType); 

     if (authorised === authorization.constants.loginRequired) { 
      event.preventDefault(); 
      $state.go('app.login'); 
     } else if (authorised === authorization.constants.notAuthorised) { 
      event.preventDefault(); 
      $state.go('app.dashboard'); 
     } 
     } 
    }); 
    } 

})(); 
+0

Grazie @ sh-ado-w, sarei attuazione di tale soluzione si è accennato in precedenza . Ti farò sapere se funziona o no. – CalmWinds

+2

Link non funziona più. Meglio pubblicare contenuti in SO che link al di fuori di esso. – eabates

+1

Ho aggiunto il codice dalla mia applicazione che, credo, era basato su quell'articolo. – Adrian

Problemi correlati