2009-11-09 24 views
8

Me gustaría configurar una aplicación ASP.NET MVC multi-tenant. Idealmente, esta aplicación tendría una ruta con {tenant}/{controller}/{action}/{id}, cada tenant representando una instancia lógica de la aplicación (simplemente cuentas de usuarios múltiples independientes)Configurar una ruta {arrendatario}/{controlador}/{acción}/{id} con ASP.NET MVC?

Los detalles detallados de cómo esto todavía no está claro para mí. ¿Hay alguna guía disponible para configurar dicho esquema de múltiples inquilinos con ASP.NET MVC?

Respuesta

12

Actualmente estoy trabajando en un proyecto similar utilizando ASP.Net MVC, Autenticación de formularios y los proveedores de SQL para Membresía/Roles/Perfil. Aquí es el enfoque que estoy tomando:

  1. Registrar la ruta por defecto como `{inquilino}/{controlador}/{acción}/{id}

  2. cambiar el comportamiento predeterminado de la FormsAuthenticationService que viene con la plantilla MVC estándar. Debe establecer UserData del ticket de autenticación para incluir el nombre del inquilino (de su ruta).

    public void SignIn(string userName, bool createPersistentCookie, string tenantName) 
    { 
        var ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(30), 
                   createPersistentCookie, tenantName); 
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket)); 
        HttpContext.Current.Response.AppendCookie(cookie); 
    } 
    
  3. En el archivo Global.asax que hacer algunas comprobaciones de seguridad y permitir que el inquilino partioning de usuarios entre los inquilinos en una base de datos de miembros

    protected void Application_AuthenticateRequest(object sender, EventArgs e) 
    { 
        //Since this method is called on every request 
        //we want to fail as early as possible 
        if (!Request.IsAuthenticated) return; 
        var route = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context)); 
        if (route == null || route.Route.GetType().Name == "IgnoreRouteInternal") return; 
        if (!(Context.User.Identity is FormsIdentity)) return; 
        //Get the current tenant specified in URL 
        var currentTenant = route.GetRequiredString("tenant"); 
        //Get the tenant that that the user is logged into 
        //from the Forms Authentication Ticket 
        var id = (FormsIdentity)Context.User.Identity; 
        var userTenant = id.Ticket.UserData; 
        if (userTenant.Trim().ToLower() != currentTenant.Trim().ToLower()) 
        { 
         //The user is attempting to access a different tenant 
         //than the one they logged into so sign them out 
         //an and redirect to the home page of the new tenant 
         //where they can sign back in (if they are authorized!) 
         FormsAuthentication.SignOut(); 
         Response.Redirect("/" + currentTenant); 
         return; 
        } 
        //Set the application of the Sql Providers 
        //to the current tenant to support partitioning 
        //of users between tenants. 
        Membership.ApplicationName = currentTenant; 
        Roles.ApplicationName = currentTenant; 
        ProfileManager.ApplicationName = currentTenant; 
    } 
    
  4. partición cada uno de los inquilinos de datos. Aquí hay dos opciones:

    4a. Use una base de datos separada para cada inquilino. Esto proporciona la mejor seguridad de datos para sus inquilinos. En la base de datos de membresía compartida, agregue una tabla que esté codificada en una aplicación única para cada inquilino y use esta tabla para almacenar y recuperar la cadena de conexión basada en el inquilino actual.

    4b. Almacene todos los datos en una base de datos y clave cada tabla en la identificación única del inquilino. Esto proporciona un poco menos de seguridad de datos para sus inquilinos, pero usa solo una licencia de SQL Server.

+2

Disculpe la respuesta obsoleta, pero Estoy trabajando en algo similar y creo que su solución podría funcionar, sin embargo, los documentos dicen que solo hay un único proveedor predeterminado para todas las solicitudes que ingresan al servidor. Entonces, creo que establecer el nombre de la aplicación puede ser una condición de carrera. –

+0

CShipley, tienes toda la razón. Cuando usé esta solución yo mismo casi me volví loco al intentar solucionar problemas una vez que tuve usuarios concurrentes de diferentes inquilinos. Creo que el camino es escribir la pieza de autenticación desde cero o implementar su propio proveedor de membresía. Elegí pasar a una instancia separada de la aplicación para cada inquilino hasta que pude obtener los detalles de un esquema de autenticación personalizado resuelto. –

+0

¿Cómo maneja a un usuario que puede actuar en representación de más de un inquilino? –

2
+0

La cuestión vinculada es relevante, pero lamentablemente no se publicaron buenas respuestas. De hecho, la única publicación relevante enlaza a otra publicación, con respuestas aún menos relevantes :-( –

+0

Esa suposición Supongo que esperaré hasta que encuentres la respuesta y usaré lo que encuentres a continuación: D –

+0

¡Gracias, estos enlaces son geniales! –

Cuestiones relacionadas