2012-04-17 86 views
1

我想询问您对我处理多租户的方式的看法。我“米使用MVC3(切换到MVC4)和EF作为我的后端我使用一个单一的应用程序,共享模式多租户下面是代码:。在MVC上处理多租户

public abstract class Service<T> where T : Entity 
{ 
    private Repository<T> _repo; 
    public Service() 
    { 
     _repo = new Repository<T>(); 
    } 

    public bool Authenticate(int id) 
    { 
     //var companyInfo = _authorizationRepository.GetApiKey(apiKey); 
     int tenantId = 0; // replaced by companyInfo using repository 
     var entity = _repo.GetQuery(tenantId).Where(e => e.Id == id).First(); 

     if (tenantId != entity.TenantId) 
      throw new ArgumentException(); 

     return true; 
    } 
} 

public class EmployeeService : Service<Employee> 
{ 
    private EmployeeRepository employeeRepository; 
    public EmployeeService() 
    { 
     employeeRepository = new EmployeeRepository(); 
    } 

    public Employee GetEmployeeById(int employeeId) 
    { 
     this.Authenticate(employeeId); 
     return employeeRepository.GetById(employeeId); 
    } 
} 

public class Entity 
{ 
    public int Id { get; set; } 
    public int TenantId { get; set; } 
} 

当然DI会在那里,以及但是简单我在这里(暂时)删除了它们,我在服务层使用了泛型(对此感觉很脏),因为我在比较TenantId和将在类上传递的正确实体时遇到了困难。这个使用FilterAttributes,但我没有任何想法如何处理你的multitenancy问题?设计是否存在一些长期可能遇到的重要缺陷?如果你有一些使用FilterAttributes的示例,那将是一个很大的帮助。

Th anks!

+0

为什么Multitenancy甚至是Web应用程序中的一个问题? – Tejs 2012-04-17 14:32:40

+0

@Tejs对我来说关心的是我如何处理路由。基本上tenant1.domain.com和domain.com/tenant2都必须是有效的,并指向特定租户 – MikeSW 2012-04-17 14:47:17

+0

这很酷,但该特定的URL方案与您决定使用的持久层无关。我想我想知道你的问题是什么。 – Tejs 2012-04-17 14:48:23

回答

2

我们正在构建相当大的多租户web应用程序。那么它并不像看起来那么简单,但是一旦你建立了你的架构,它就很简单。我们正在深入开发,但你可以看看nanocms.codeplex.com中的开源部分(我们没有上传数据库喷射对接,我们将在几天内)

由于这是一个相当广泛的问题,我会尝试总结一些问题和解决方案。

首先,您需要确定每个请求的租户。我们有一个全局动作过滤器,用于解析url并将其与数据库中的数据进行比较。当然,你必须缓存所有的数据,以免对数据库进行调用。您不能在cookie或会话中保存任何内容,因为用户可以在当时访问多个租户。我建议你将这些数据放在HttpRequest Items中,这样在请求中只做一次,但仍然可以使用这些数据。

对于验证用户必须是唯一的。你必须想,如果你想给每个租户一些用户不同的权利。如果是这样,您必须编写验证码甚至属性,以便检查他在当前租户中的角色。在我们的应用中,当用户认证时,我们创建会话对象。在对象中,我们有检查租户权限的静态方法。

我建议你保持强制类型的HttpRequest项目。我们有:

public static int TenantID { 
    get { return System.Web.HttpContext.Current.Items.Contains("TenantID") ? Convert.ToInt32(System.Web.HttpContext.Current.Items["TenantID"]) : -1; } 
    set { 
     if (!System.Web.HttpContext.Current.Items.Contains("TenantID")) 
      System.Web.HttpContext.Current.Items.Add("TenantID", value); 
     System.Web.HttpContext.Current.Items["TenantID"] = value; 
    } 
} 
+0

感谢您的回复Goran。但是,您如何检查将要发布的实体是否将不会转向错误的租户。例如,TenantA将插入/选择一个项目,您如何确保TenantA不会选择/插入TenantB的数据? – gnaungayan 2012-04-17 23:21:44

+0

请解释一下您是否担心交叉发布的安全问题,或只是向正确的承租人提供正确的内容?为了安全起见,您可以使用防伪标记来防止交叉帖子。为了确保正确的内容,您必须在数据库的每个父表中都有tenantId并相应地写入查询。 – 2012-04-18 07:21:27

+0

它更像你的第二个陈述。如果有一个网址www.site.com/Employees/1(这属于TenantA数据),但TenantB已登录并对该网址进行了硬编码,那么如何阻止他查看TenantA数据? – gnaungayan 2012-04-18 13:36:19