He desarrollado una Sola Página de la Aplicación que utiliza la api REST. Se requiere que los usuarios de inicio de sesión para acceder a la aplicación. Cuando un usuario inicia una sesión en la que redirige a /panel de control. En esta dirección URL o ruta, me gustaría cargar una plantilla diferente y controlador basado en el rol del usuario (por ejemplo, normal usuario o admin usuario).

He mirado en https://github.com/angular-ui/ui-router/wiki en la sección plantillas, pero ninguna de las opciones de soporte de lo que estoy tratando de lograr.

  • Mediante templateUrl y la función (stateParams) yo no soy capaz de inyectar el servicio que me ayuda a determinar la función de usuario para que yo pueda cargar la plantilla, por ejemplo, vistas/usuario/dashboard.html o vistas/admin/dashboard.html
  • Mediante templateProvider estoy para inyectar el servicio que me ayuda a determinar la función de usuario, pero, ¿cómo puedo, a continuación, cargue la plantilla?

Cualquier solución debe cargar diferentes controladores basados en el rol de usuario, por ejemplo UserDashboardController o AdminDashboardController.

Así essentialy lo que necesita es una sola ruta que carga una plantilla diferente Y un controlador basado en una función de usuario variable que se establece en un servicio cuando un usuario inicia la sesión.

Estoy pensando a lo largo de las líneas correctas, o debería ser la aplicación de otra solución?

Cualquier ayuda sería muy apreciada.

  • Encontraste alguna solución?
  • Su objetivo es sólo para funcionalmente independientes de usuario/admin tools? Está usted preocupado acerca de la seguridad, funcionalidad, ambos? Se busca admin pantallas de ser un super-conjunto de pantallas de usuario (tener enlaces de administración y herramientas de como editar, eliminar, crear), o quieres crear completamente distintas experiencias de usuario?
  • sí, la primera opción: «buscando admin pantallas de ser un super-conjunto de pantallas de usuario (tener enlaces de administración y herramientas de como editar, eliminar, crear),`. I. e. no hay mucha diferencia entre regular de usuario y de administración de pantallas
  • Usted podría tratar de la primera solución en mi respuesta. Es la misma idea acerca de la alternancia de las funciones de la página. En este caso, no se configuran los derechos, los derechos son asumidos para ser codificada en cada función (Se podía extender en el futuro para hacer que los derechos configurable o agregar más funciones).
InformationsquelleAutor user3596298 | 2014-05-02

9 Comentarios

  1. 23

    La carga de la plantilla y el controlador basado en el rol de usuario

    Aunque técnicamente ui-router templateUrl función no admite la inyección de los servicios que usted puede utilizar templateProvider para inyectar service que tiene role variable o carga de forma asíncrona y, a continuación, utilizar $templateFactory para devolver el contenido HTML. Considere el siguiente ejemplo:

    var app = angular.module('app', ['ui.router']);
    
    app.service('session', function($timeout, $q){
        this.role = null;
    
        this.loadRole = function(){
            //load role using axax request and return promise
        };
    });
    
    app.config(function($stateProvider, $urlRouterProvider){
        $stateProvider.state('dashboard', {
            url: '/dashboard',
            templateProvider: function(session, $stateParams, $templateFactory){
              return session.loadRole().then(function(role){
                  if(session.role == 'admin'){
                    return $templateFactory.fromUrl('/admin/dashboard.html', $stateParams);
                  } else {
                    return $templateFactory.fromUrl('/user/dashboard.html', $stateParams);
                  }
              });
            }
          });
    
        $urlRouterProvider.otherwise('/dashboard');
    });

    Como para controller puede declarar que le gustaría para uso específico de controlador dentro del elemento raíz de cada plantilla con ng-controller. O también puede utilizar controllerProvider opción para inyectar service que ya han role resuelto por templateProvider. Echa un vistazo al siguiente ejemplo de controllerProvider opción dentro de ui-router estado definición:

    controllerProvider: function(session){
      if(session.role == 'admin'){
        return 'AdminCtrl';
      } else {
        return 'UserCtrl';  
      }
    }

    Por supuesto, usted puede eliminar los duplicados de este código fácilmente y definir una más accesible micro DSL para hacer la definición de reglas diferentes para determinadas funciones y vistas más fácil.

    La siguiente demo le ayudará a entender el código.

    Es este un enfoque correcto?

    Como normalmente esto depende en gran medida del contexto. Para ayudar a que venir para arriba con una respuesta permítanme sugerir siguientes preguntas primero:

    • Cuánto vistas presentado a funciones difieren?

    Vas a ocultar sólo un par de buttons y otros elementos de la acción, básicamente, una página de sólo lectura para los usuarios regulares y editable para superusuarios? Si los cambios son pequeños, probablemente me vaya con el uso de los mismos puntos de vista y sólo la ocultación de determinados elementos, probablemente, la forja de una directiva similar a ng-if que permita habilitar/deshabilitar la funcionalidad particular mediante declaración only-role='operator, admin'. Por otro lado, si vistas van a ser muy diferentes, a continuación, empleando diferentes plantillas puede simplificar marcado mucho.

    • Cuánto acciones disponible en determinadas página difieren dependiendo de papel?

    Hacer acciones que se parecen en la superficie difieren en su funcionamiento interno para diferentes funciones? En el ejemplo si usted tiene Editar acción disponible tanto para user y admin papel, pero en un caso se inicia asistente como interfaz de usuario y en otros de una forma compleja para usuarios avanzados, a continuación, tener un controller tiene más sentido. Por otro lado, si admin acciones son un superconjunto de user acciones, a continuación, tener una sola controladora parece más fácil de seguir. Tenga en cuenta que en ambos casos manteniendo controller cosas paga – sólo deben pegamento vistas a un comportamiento que es encapsulado en servicios/ver modelos/models/escoger un nombre

    • Va a tener muchos contextualmente separado enlaces que conduce a particular página de diferentes lugares de la app?

    Por ejemplo, es capaz de proporcionar navegación a particular página simplemente escribir ui-sref="dashboard" independientemente de que el usuario actual role puede ser beneficioso, si es que existe en diversos contextos. Si ese es el caso, de haber definido bajo una sola ruta/estado parece más fácil de mantener, a continuación, una lógica condicional se utiliza para construir diferentes ui-sref/ng-href basado en papel. Sin embargo, usted también podría definir rutas/estados de forma dinámica basándose en el rol de usuario – cargado dinámicamente o no

    • Se opiniones y acciones disponibles para los diferentes roles en particular página evolucionar por separado o juntos?

    A veces tenemos la primera generación de características para los usuarios regulares, a continuación, para la premium y luego para el final. No es inusual para dividir el trabajo en las páginas de user y admin entre los miembros del equipo, especialmente si claro los límites se pueden extraer fácilmente. En caso de haber separado views y controllers puede simplemente los desarrolladores de trabajo evitando los conflictos. Por supuesto que no todos los arco iris y unicornios – equipo debe ser muy disciplinado para eliminar la duplicación que lo más probable es que va a suceder.

    Espero que mis sugerencias te ayudarán a decidir.

    • Gracias. Pero en el caso de admin es el codificado papel. Pero voy a recibir de usuario-función de forma asíncrona mediante petición AJAX. Así que no estoy seguro de que esto va a funcionar: role = injector.get('session').role,
    • He actualizado mi respuesta para apoyar la resolución de role de forma asincrónica
    • Wow! Gran respuesta! +100
  2. 15

    Estoy pensando a lo largo de las líneas correctas, o debería ser la aplicación de
    otra solución?

    De la OMI, no debe hacerlo de esta manera.

    Aquí, propongo 2 otras soluciones dependiendo de cómo su aplicación está implementada.

    1) Si los derechos de sus funciones puede ser configurado (usted podría tener una página separada para configurar sus roles, asignar derechos a sus funciones,…). A continuación, utilice sólo 1 de plantilla y 1 controlador para su roles (usuarios normales, de administración de los usuarios, y más……) y el uso ng-show, ng-class,.. para mostrar el código HTML en consecuencia.

    En este caso, no nos importa mucho si el usuario es un usuario normal, o un usuario administrador, que es sólo el nombre de nuestro papel. Lo que nos importa es el derechos y es dinámico => por lo Tanto, se debe mostrar el código html de forma dinámica basándose en la configuración de los derechos (por cierto, también hay controles en el lado del servidor cuando los usuarios realizan una acción para evitar que el usuario, desde la creación de un malicioso petición http y la publicación de servidor). Si usamos plantillas separadas para eso, hay innumerables de los casos.

    El punto de esta solución es que las funciones de la página son el mismo a sus funciones, sólo necesita mostrar/ocultar las funciones de la página basado en el usuario.

    2) Si los derechos de las funciones se fija (no se puede configurar) y el funcionalidad de las opiniones de los usuarios normales y administración de los usuarios son diferentes. Es mejor usar separado los estados para que estos puntos de vista y autorizar el acceso a estos puntos de vista basados en el usuario que ha iniciado sesión (por cierto, también hay autorización en el lado del servidor cuando los usuarios realizan una acción).

    La razón es: el usuario administrador de la vista normal y vista de usuario se han funcionalidad diferente (que deben estar separados unos de otros)

    • Supongo que la mitad de una recompensa es mejor que ninguna recompensa. Debería haber sido completa. A continuación, de nuevo, duro para satisfacer a alguien que no sabe lo que quiere.
  3. 7

    Si usted está utilizando la versión de angular mayor que 1.2 usted puede hacer una directiva con un templateUrl como una función.

    Así que la idea básica es que usted tiene una vista de panel que tiene una costumbre de la directiva en lo que va a determinar el modelo basado en el nivel de usuario. Así que algo como esto:

    (function () {
      'use strict';
      angular.module('App.Directives')
        .directive('appDashboard', ['UserManager', function (UserManager) {
          return {
            restrict: 'EA',
            templateUrl: function(ele, attr){
                if (UserManager.currentUser.isAdmin){
                    return 'admin.html';
                }else{
                    return 'user.html';
                }
            }
          };
        }]);
    })(); 
    • esto sólo se ejecuta una vez y tiene problemas si el usuario cierra la sesión e inicia sesión de nuevo con otro papel.
  4. 4

    I. Hacer no uso «…única ruta que carga una plantilla diferente…», sería mi sugerencia, mi respuesta.

    Si es posible:

    Tratan de dar un paso atrás y reconsiderar todo el diseño y

    Intente debilitan el sentido que nuestra aplicación usuarios están interesados en url.

    No lo son. Y si realmente entender lo que es url, barra de direcciones… ellos lo usan para copy, send y paste… no investigar sus partes…

    II. Sugerencia: Aplicar el uso de la interfaz de usuario del router estados:

    UI-Router es organizado alrededor de los estados, que puede OPCIONALMENTE han rutas, así como cualquier otro comportamiento, que se adjunta…

    Que significa, pensemos en nuestra aplicación como grupo a la jerarquía de los estados. Ellos pueden tener url definido , , pero no tienen que (por ejemplo, estado de error sin url)

    III. ¿Cómo podemos beneficio de la construcción de nuestra aplicación cerca de los estados unidos?

    Separación de preocupación – debe ser nuestro objetivo.

    La estado es una unidad que reúne a algunos ver/controladores de, resoluciones, de datos personalizados

    Que significa, que podría ser más estados la reutilización de vistas, controladores de, etc. Tal estados podría realmente diferentes (mismo punto de vista, controlador diferente). Pero son solo propósito – están ahí para tratar algunos de los escenarios:

    • administración de Usuario/Emplyoee registro
    • lista de Usuario/Empleado – información ala PhoneList (correo electrónico, teléfono…)
    • La administración de la seguridad – ¿cuáles son los derechos de un Usuario

    Y otra vez, no puede ser de muchos, muchos estados. Tener incluso cientos de miembros no será problema de rendimiento. Estos son sólo definiciones, un conjunto de referencias a otras piezas, que debe ser utilizado … más tarde… si es realmente necesario.

    Una vez que hemos definido casos de uso, historias de usuario en el nivel de la estado, podemos agruparlos en conjuntos/jerarquías.

    Estos grupos podría ser, más tarde, presentó a los diferentes Roles de usuario en un formato diferente (diferentes elementos de menú)

    Pero al final, hemos ganado mucha libertad y simplificado el mantenimiento

    IV. Mantener la aplicación que se ejecuta y creciente

    Si hay algunos estados, maintainanace no parece ser un problema. Pero podría suceder que la aplicación tendrá éxito. Tener éxito y crecer… en el interior de su diseño.

    Desdoblamiento de la sate definiciones (como una unidad de trabajo) y sus jerarquías (que la Función de usuario pueden acceder a los estados) para simplificar su gestión.

    Appling de seguridad fuera de los estados (detectores de Eventos ala '$stateChangeStart') es mucho más fácil, a continuación, que nunca termina de refactorización de la plantilla de los Proveedores. También, la parte principal de seguridad, debe aplicarse en un servidor, independientemente de lo que la interfaz de usuario permite

    V. Resumen:

    Aunque no es una gran característica como un templateProvider, lo que podría hacer algunas cosas interesantes para nosotros (por ejemplo, aquí: Cambiar el Menú de Navegación de uso de la interfaz de usuario del Router en AngularJs)…

    … no debemos utilizarlo para la seguridad. Que podría ser implementado como un menu de la jerarquía, construido a partir de los estados existentes, basado en la Función actual. Los detectores de eventos debe comprobar si el usuario está llegando a conceder estado, pero el control debe aplicarse en un servidor…

    • gracias. Suena bien, pero por favor, puedes proporcionar algún ejemplo?
    • No estoy seguro si este diseño sugerencia se podría dar con un «tan simple como el ejemplo»… pero va a pensar acerca de esto más tarde hoy… o más tarde. La parte esencial de mi punto de vista es: Definir los estados tan simple como sea posible. No podía ser de muchos de ellos. Una vez que se crea la navegación de los usuarios – hacer Papel dependiente (más navi configuración para cada Función). Si es necesario, introducir algunos de verificación en los eventos… pero el verdadero seccurity aplicar en un servidor (Obtener datos sólo si el usuario ha requerido de Papel). Así que, esto es más un diseño/architetural principio, que un simple caso de uso responder… Va a estar contento si esto podría ayudar, aunque sea un poco… más adelante 😉
    • Veo un problema con el enfoque ofrecido por esta respuesta. El usuario abre la ww.someapp.com/ y se redirige al angulares a #!/ que se supone que el usuario puede estar firmados o no firmados en este momento. Obviamente, los usuarios registrados no necesita en ver de «marketing» en la página de inicio, prefieren ser redirigido eficazmente a panel cuando visita «/#!/» o «/» ruta de acceso.
  5. 3

    Usted realmente no tiene que hacerlo con el router.

    La cosa más simple es utilizar un único modelo para todas las funciones y el uso dinámico ng-incluir dentro de ella. Supongamos que usted tiene inyector en el $scope:

    <div ng-include="injector.get('session').role+'_dashboard.html'"></div>

    Por lo que debe tener user_dashboard.html y admin_dashboard.html vistas. Dentro de cada uno de ustedes puede solicitar controlador separado, por ejemplo user_dashboard.html:

    <div id="user_dashboard" ng-controller="UserDashboardCtrl">
        User markup
    </div>
  6. 3

    He empleado la siguiente solución (que puede no ser ideal, pero se ha trabajado para mí en este tipo de escenarios):

    1. Especificar el controlador en la propia plantilla, utilizando ngController.

    2. De carga de la plantilla mediante un genérico de nombre de la vista (por ejemplo,views/dashboard.html).

    3. Cambiar lo que views/dashboard.html se refiere a mediante el uso de $templateCache.put(...) cada vez que el usuario ha iniciado la sesión-cambios de rol.


    Aquí es un striiped abajo ejemplo del enfoque:

    app.controller('loginCtrl', function ($location, $scope, User) {
    ...
    $scope.loginAs = function (role) {
    //First set the user role
    User.setRole(role);
    //Then navigate to Dashboard
    $location.path('/dashboard');
    };
    });
    //A simplified `User` service that takes care of swapping templates,
    //based on the role. ("User" is probably not the best name...)
    app.service('User', function ($http, $templateCache) {
    var guestRole = 'guest';
    var facadeUrl = 'views/dashboard.html';
    var emptyTmpl = '';
    var errorTmpl = 'Failed to load template !';
    var tempTmpl  = 'Loading template...';
    ...
    //Upon logout, put an empty template into `$templateCache`
    this.logout = function () {
    this.role = guestRole;
    $templateCache.put(facadeUrl, emptyTmpl);
    };
    //When the role changes (e.g. upon login), set the role as well as the template
    //(remember that the template itself will specify the appropriate controller) 
    this.setRole = function (role) {
    this.role = role;
    //The actual template URL    
    var url = 'views/' + role + '/dashboard.html';
    //Put a temporary template into `$templateCache`
    $templateCache.put(facadeUrl, tempTmpl);
    //Fetch the actual template (from the `$templateCahce` if available)
    //and store it under the "generic" URL (`views/dashboard.html`)
    $http.get(url, {cache: $templateCache}).
    success(function (tmpl) {
    $templateCache.put(facadeUrl, tmpl);
    }).
    error(function () {
    //Handle errors...
    $templateCache.put(facadeUrl, errorTmpl);
    });
    };
    //Initialize role and template        
    this.logout();
    });
    //When the user navigates to '/dashboard', load the `views/dashboard.html` template.
    //In a real app, you should of course verify that the user is logged in etc...
    //(Here I use `ngRoute` for simplicity, but you can use any routing module.)
    app.config(function ($routeProvider) {
    $routeProvider.
    when('/dashboard', {
    templateUrl: 'views/dashboard.html'
    }).
    ...
    });

    Ver, también, este breve demostración.


    (Yo uso ngRoute por simplicidad, pero no es cualquier diferencia dado que todo el trabajo es hecho por el User servicio).

  7. 1

    Sin necesidad de una larga explicación aquí.

    Utilizar resolver y de cambio de $ruta.$$de la ruta.templateUrl, o el uso routeChangeError por el paso de la nueva carretera o el parámetro relevante para la promesa.

    var md = angular.module('mymodule', ['ngRoute']);
    md.config(function($routeProvider, $locationProvider) {
    $routeProvider.when('/common_route/:someparam', {
    resolve: {
    nextRoute: function($q, $route, userService) {
    defer = $q.defer()
    userService.currentRole(function(data) { defer.reject({nextRoute: 'user_based_route/'+data) });
    return defer.promise;
    }
    }
    });
    $rootScope.$on("$routeChangeError", function(evt, current, previous, rejection) {
    if (rejection.route) {
    return $location.path(rejection.route).replace();
    }
    });
    });
  8. 1

    Sé que esto ha sido un tiempo desde que esta pregunta fue publicado, pero voy a añadir a mi respuesta, ya que yo el método que yo uso es diferente de las otras respuestas aquí.

    En este método, yo soy la separación completa de la ruta y de la plantilla de url basado en que la función del usuario y redirigir al usuario a la página de índice si están en una ruta que no está autorizado a ver.

    Con la interfaz de usuario del Router, yo, básicamente, agregar un atributo de datos como este para el estado:

    .state('admin', {
    url: "/admin",
    templateUrl: "views/admin.html",
    data: {  requireRole: 'admin' }
    })

    Cuando el usuario está autenticado, puedo almacenar sus datos en la localstorage y $rootscope desde el controlador como este:

    var role = JSON.stringify(response.data); //response from api with role details
    //Set the stringified user data into local storage
    localStorage.setItem('role', role);
    //Putting the user's role on $rootScope for access by other controllers
    $rootScope.role = response.data;

    Por último, yo uso el $stateChangeStart para comprobar el papel y redirigir al usuario si el usuario no se supone que para ver la página:

    .run(['$rootScope', '$state', function($rootScope, $state) {
    //$stateChangeStart is fired whenever the state changes. We can use some parameters
    //such as toState to hook into details about the state as it is changing
    $rootScope.$on('$stateChangeStart', function(event, toState) {
    var role = JSON.parse(localStorage.getItem('role'));
    $rootScope.role = role;
    //Redirect user is NOT authenticated and accesing private pages
    var requireRole = toState.data !== undefined
    && toState.data.requireRole;
    if( (requireRole == 'admin' && role != 'admin')) )
    {
    $state.go('index');
    event.preventDefault();
    return;
    }
    }
    });

    Adicional a lo anterior, aún se necesita hacer de lado de servidor de verificación de autorización antes de mostrar los datos al usuario.

Dejar respuesta

Please enter your comment!
Please enter your name here