我想设置一个多租户 ASP.NET MVC 应用程序。理想情况下,这个应用程序应该有一个带有 的路由{tenant}/{controller}/{action}/{id}
,每个tenant
代表应用程序的一个逻辑实例(只是独立的多用户帐户)
细粒度的细节如何做到这一点对我来说仍然很不清楚。任何可用于使用 ASP.NET MVC 设置此类多租户方案的指南?
我想设置一个多租户 ASP.NET MVC 应用程序。理想情况下,这个应用程序应该有一个带有 的路由{tenant}/{controller}/{action}/{id}
,每个tenant
代表应用程序的一个逻辑实例(只是独立的多用户帐户)
细粒度的细节如何做到这一点对我来说仍然很不清楚。任何可用于使用 ASP.NET MVC 设置此类多租户方案的指南?
我目前正在使用 ASP.Net MVC、Forms Authentication 和用于 Membership/Roles/Profile 的 SQL 提供程序进行类似的项目。这是我正在采取的方法:
将默认路由注册为 `{tenant}/{controller}/{action}/{id}
更改标准 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);
}
在您的 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;
}
对每个租户数据进行分区。这里有两个选项:
4a。为每个租户使用单独的数据库。这为您的租户提供了最佳的数据安全性。在共享成员数据库中,为每个租户添加一个以唯一 appid 为键的表,并使用此表存储和检索基于当前租户的连接字符串。
4b。将所有数据存储在一个数据库中,并在唯一的租户 ID 上为每个表键入密钥。这为租户提供的数据安全性略低,但仅使用一个 SQL Server 许可证。