使用 ASP.NET MVC 设置路由 {tenant}/{controller}/{action}/{id}?

发布于 2024-08-09 23:59:38 字数 211 浏览 5 评论 0 原文

我想设置一个多租户 ASP.NET MVC 应用程序。理想情况下,此应用程序应具有包含 {tenant}/{controller}/{action}/{id} 的路由,每个 tenant 代表应用程序的一个逻辑实例(简单地说独立的多用户帐户)

我仍然不清楚如何做到这一点。有任何指南可用于使用 ASP.NET MVC 设置此类多租户方案吗?

I would like to setup a multi-tenant ASP.NET MVC app. Ideally, this app would have a route with {tenant}/{controller}/{action}/{id}, each tenant representing an logical instance of the app (simply independent multi-user accounts)

The fine grained details how do that are still quite unclear to me. Any guide available to setup such multi-tenant scheme with ASP.NET MVC?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

赤濁 2024-08-16 23:59:38

我目前正在使用 ASP.Net MVC、表单身份验证和用于成员/角色/配置文件的 SQL 提供程序开发一个类似的项目。这是我正在采取的方法:

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

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

    public void SignIn(string userName, bool createPersistentCookie, string tenantName)
    {
        var Ticket = new FormsAuthenticationTicket(1, 用户名, DateTime.Now, DateTime.Now.AddMinutes(30),
                                                   创建持久性Cookie,租户名称);
        var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
        HttpContext.Current.Response.AppendCookie(cookie);
    }
    
  3. 在您的 global.asax 文件中执行一些租户安全检查并允许在一个成员数据库中的租户之间进行用户分区

    protected void Application_AuthenticateRequest(对象发送者,EventArgs e)
    {
        //因为每个请求都会调用这个方法
        //我们希望尽早失败
        if (!Request.IsAuthenticated) 返回;
        var 路由 = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));
        if (route == null || route.Route.GetType().Name == "IgnoreRouteInternal") return;
        if (!(Context.User.Identity 是 FormsIdentity)) return;
        //获取URL中指定的当前租户 
        var currentTenant = route.GetRequiredString("租户");
        //获取用户登录的租户
        //来自表单身份验证票证
        var id = (FormsIdentity)Context.User.Identity;
        var userTenant = id.Ticket.UserData;
        if (userTenant.Trim().ToLower() != currentTenant.Trim().ToLower())
        {
            //用户正在尝试访问不同的租户
            //比他们登录的那个要多,所以将他们注销
            //an并重定向到新租户的主页
            //他们可以重新登录的地方(如果他们获得授权!)
            FormsAuthentication.SignOut();
            Response.Redirect("/" + currentTenant);
            返回;
        }
        //设置Sql Providers的应用 
        //给当前租户支持分区
        //租户之间的用户数。
        Membership.ApplicationName = currentTenant;
        Roles.ApplicationName = currentTenant;
        ProfileManager.ApplicationName = 当前租户;
    }
    
  4. 对每个租户数据进行分区。这里有两个选项:

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

    4b。将所有数据存储在一个数据库中,并为每个表设置唯一的租户 ID。这为您的租户提供的数据安全性稍差,但仅使用一个 SQL Server 许可证。

I am currently working on a similar project using ASP.Net MVC, Forms Authentication and the SQL providers for Membership/Roles/Profile. Here is the approach I am taking:

  1. Register the default route as `{tenant}/{controller}/{action}/{id}

  2. Change the default behavior of the FormsAuthenticationService that comes with the standard MVC template. It should set the UserData of the authentication ticket to include the tenant name (from your route).

    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. In your global.asax file to do some tenant security checking and allow partioning of users between tenants in one membership database

    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. Partition each tenants data. Here are two options:

    4a. Use a separate database for each tenant. This provides the best data security for your tenants. In the shared membership database, add a table that is keyed on unique appid for each tenant and use this table to store and retrieve the connection string based on the current tenant.

    4b. Store all data in one database and key each table on the unique tenant id. This provides slightly less data security for your tenants but uses only one SQL Server license.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文