【问题标题】:Setup a route {tenant}/{controller}/{action}/{id} with ASP.NET MVC?使用 ASP.NET MVC 设置路由 {tenant}/{controller}/{action}/{id}?
【发布时间】:2009-11-09 09:15:38
【问题描述】:

我想设置一个多租户 ASP.NET MVC 应用程序。理想情况下,这个应用程序应该有一个带有{tenant}/{controller}/{action}/{id} 的路由,每个tenant 代表应用程序的一个逻辑实例(只是独立的多用户帐户)

我还不清楚具体的细节是如何做到的。有任何指南可用于使用 ASP.NET MVC 设置此类多租户方案吗?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-routing multi-tenant


    【解决方案1】:

    我目前正在使用 ASP.Net MVC、Forms Authentication 和用于 Membership/Roles/Profile 的 SQL 提供程序进行类似的项目。这是我正在采取的方法:

    1. 将默认路由注册为`{tenant}/{controller}/{action}/{id}

    2. 更改标准 MVC 模板附带的 FormsAuthenticationService 的默认行为。它应该将身份验证票证的 UserData 设置为包含租户名称(来自您的路由)。

      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. 在您的 global.asax 文件中进行一些租户安全检查并允许在一个成员数据库中的租户之间划分用户

      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. 对每个租户数据进行分区。这里有两个选项:

      4a。为每个租户使用单独的数据库。这为您的租户提供了最佳的数据安全性。在共享成员数据库中,为每个租户添加一个以唯一 appid 为键的表,并使用该表存储和检索基于当前租户的连接字符串。

      4b。将所有数据存储在一个数据库中,并在唯一的租户 ID 上为每个表键入密钥。这为您的租户提供的数据安全性略低,但仅使用一个 SQL Server 许可证。

    【讨论】:

    • 抱歉,回复过时了,但我正在研究类似的东西,我认为您的解决方案可能有效,但是文档说只有一个默认提供程序可以处理所有进入服务器。所以,我认为设置应用程序名称可能是一个竞争条件。
    • CShipley,你说得对。当我自己使用这个解决方案时,一旦我有来自不同租户的并发用户,我几乎要疯狂地尝试解决问题。我认为方法是从头开始编写身份验证部分或实现您自己的成员资格提供程序。我选择为每个租户移动到应用程序的单独实例,直到我能够制定出自定义身份验证方案的详细信息。
    • 如何处理可以代表多个租户行事的用户?
    【解决方案2】:

    你会发现findtheselinksuseful

    【讨论】:

    • 链接的问题确实相关,但遗憾的是没有发布好的答案。实际上,唯一相关的帖子链接到另一个帖子,相关答案甚至更少:-(
    • 那个sux。我想我会等到你找到答案,然后我会使用你找到的答案。 :D
    • 更清楚地分解这些链接。匆忙中,我只是点击了一个。
    • @FreshCode 慢点,你会没事的。 ;)
    猜你喜欢
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-06
    相关资源
    最近更新 更多