多租户应用程序允许一个用户访问许多租户帐户?

时间:2013-04-15 23:04:12

标签: c# ajax asp.net-mvc multi-tenant jsonresult

我使用每个租户模型一个数据库编写多租户应用程序。我允许每个用户帐户访问多个租户(只要该租户已授予他们访问权限)

发送到浏览器的每个页面都包含Site.Master中的当前TenantId

<%= Html.Hidden("TenantId") %>

但是当从浏览器发出任何请求(提交按钮,AJAX GET或AJAX POST)时,实际上不会检查此TenantId是否与用户当前的TenantId匹配。

现在,如果用户打开一个选项卡,TenantId = 1,则连接到另一个选项卡中的另一个租户,TenantId = 2,然后切换回第一个选项卡,它可以访问租户2中的数据。

我该怎么做才能解决这个问题?我有大量现有的ActionResult和JsonResult方法,我不想通过它们中的每一个并添加

if (request.TenantId != user.CurrentTenantId) return false

因为这将是大量的重复工作

我可以将基本控制器更改为始终读取TenantId的值吗?这可能适用于提交的请求(ActionResult),但是AJAX请求呢?

如何在不更改每个现有AJAX方法的情况下检查JsonResult操作中页面的TenantId(有很多方法)?

4 个答案:

答案 0 :(得分:2)

您可以在Global.asax.cs文件中检查您的Application_Request事件。如果您需要通过MVC模型绑定填充,那么可以编写一个自定义ActionFilter来检查它并通过GlobalFilter将其注册到所有操作。

答案 1 :(得分:0)

您可以编写自己的过滤器:

How do I get certain code to execute before every single controller action in ASP.NET MVC 2? Executing code before any action

当然,你的问题没有现成的答案。你需要编写自己的逻辑,如何处理tenantId。例如,在每个操作上,检查它是否与当前会话租户ID重定向不相等。或者把它放在cookie中并每次在过滤器中检查id是否相等。由你决定。从我的角度来看,cookie更受欢迎。但它吃了流量。

答案 2 :(得分:0)

如果我理解正确,用户可以同时打开2个不同的标签,每个标签都有不同的租户。每个页面都应显示与每个租户相关的数据。

这意味着需要丢弃涉及cookie或会话的解决方案,因为租户特定于每个浏览器选项卡。

在阅读Cyril Gupta建议的答案时,我理解每个页面上隐藏的tenantId可能无法在每个AJAX请求中提交。 当然,一种解决方案可能是修改您的应用程序,并确保每个AJAX请求始终如此。 否则,这也将丢弃基于请求参数的全局过滤器,因为tenantId可能并不总是在那里。

我认为最好的选择是在包含tenantId的URL中添加一个段。 例如,用以下路线替换默认路线(如果您有许多不同的路线,则需要非常小心以避免路线碰撞):

routes.MapRoute(
            name: "Default",
            url: "{tenant}/{controller}/{action}/{id}",
            defaults: new { tenant = "defaultTenant", controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

通过这种方式,您可以确保在每个请求中始终提交租户,并且您还可以拥有2个不同的选项卡,其中不同的租户会显示相应的数据。

如何恢复路段的价值有不同的选择。

绑定将自动填充操作方法上名为“tenant”的任何参数的值,或者作为action方法的参数的模型类中名为“tenant”的任何参数:         公共ActionResult Foo(FooModel模型,字符串租户)         {             // tenant和model.tenant都将包含URL段的值             return View();         }

您还可以编写一个访问路由参数值的过滤器(RouteData是作为过滤方法参数接收的ActionExecutingContextActionExecutedContext类的属性),并执行一些逻辑。然后将过滤器设置为应用程序或基本控制器中的全局过滤器:

public class FooFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var tenant = filterContext.RouteData.Values["tenant"]
        //do whatever you need to do before executing the action, based on the tenant 
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var tenant = filterContext.RouteData.Values["tenant"]
        //do whatever you need to do after executing the action, based on the tenant
    }
}

最后一个选项是直接访问基本控制器类上的RouteData参数。 (因为RouteData是基本MVC Controller类的属性)

只要您使用Html和Ajax帮助程序生成URL,URL的租户段就会保留在您的链接中。但是,如果你有jquery代码直接发送带有硬编码URL的AJAX调用,那么你需要更新该代码,以便考虑新的url段。

最后,如果tenantId值不是像整数那样非常用户友好,那么每个租户都可以拥有唯一的名称,并使用URL中的名称。然后,您将添加一些逻辑,将其映射到应用程序所需的整数值。

答案 3 :(得分:-1)

您可以在控制器级别应用过滤器并检查正在发送的tenantid。控制器级过滤器不应该比动作过滤器困难。对于我的项目,我需要以类似的方式检查授权,但我覆盖了控制器类,然后从我自己的控制器类继承,因为我有一些非常特殊的需求。

您打算在哪里将租户ID存储在客户端?在我看来,你应该使用会话对象来做到这一点。