我使用标准的ASP.Net Identity cookie身份验证为我的ASP.NET MVC项目设置了多租户。因此,我可以在mysite.com上访问主租户(常规租户以及访问某些租户管理工具),并在t1.mysite.com,t2.mysite.com上访问不同的租户。
在t1.mysite.com上进行的登录在t2.mysite.com上无效,这正是我想要的。但是,如果我登录mysite.com,那么在登录时,访问tX.mysite.com,看起来好像我还在登录。即使我拥有的应用程序的身份也不存在。
有没有办法确保收到的mysite.com身份验证cookie在tX.mysite.com上无效,这样管理员就不会意外地进入非工作租户(GUI可见,但你可以因为登录mysite.com在tx.mysite.com上无效所以不做任何事情,所以最好只显示登录界面。
答案 0 :(得分:0)
在App_Start\Startup.Auth.cs
文件中,您应该了解OnValidateIdentity
:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<Infrastructure.Identity.UserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie))
},
// Other stuff
});
请参阅参数validateInterval
- 默认设置为30分钟。这就是实际将cookie与数据库中的值进行比较的频率。
将值更改为TimeSpan.FromSeconds(30)
。这将每隔30秒将cookie与数据库中的值进行比较,如果租户的身份无效,将向用户显示登录门户。
您也可以将其更改为0,但我觉得这会使您的数据库超载 - 在每次请求时都会有几次调用数据库。
CookieDomain
上还有一个属性CookieauthenticationOptions
属性:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// other stuff
CookieDomain = "example.com"
});
这可能对您有所帮助,但由于此项在管道中如此配置,因此在运行时可能很难重新配置。
另一种选择是拥有多个cookie认证中间件,但这只有在您的租户数量众所周知且非常有限的情况下才有效:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// other stuff
AuthenticationType = "myTenant1",
CookieDomain = "t1.example.com"
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// other stuff
AuthenticationType = "myTenant2",
CookieDomain = "t2.example.com"
});
但这可能会给你带来比实际值得更多的麻烦。
答案 1 :(得分:0)
所以我找到了解决问题的另一种方法。我似乎可以直接挂钩到cookie身份验证中,只要拒绝来自错误租户的身份。
所以我编写了自定义CookieAuthenticationProvider
public class TenantCookieAuthenticationProvider: CookieAuthenticationProvider
{
public override Task ValidateIdentity(CookieValidateIdentityContext context)
{
string tenantId = SubdomainRoute.GetSubdomain(context.Request.Host.Value);
if (!string.IsNullOrEmpty(tenantId)) // we're trying to access mysite.com from x.mysite.com
{
context.RejectIdentity();
return Task.FromResult<int>(0);
}
return base.ValidateIdentity(context);
}
}
并将其挂钩到Startup.cs
中的身份验证管道中app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new TenantCookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
当然,这只是战斗的一半......另一半不是拒绝身份,以防它是一个有效的租户用户。由于我在创建用户时添加了tenantId作为声明,因此我可以提取并比较这些声明,以免拒绝有效的租户用户。所以我改编了ValidateIdentity如下
public override Task ValidateIdentity(CookieValidateIdentityContext context)
{
System.Security.Claims.Claim tenantClaim = context.Identity.Claims.FirstOrDefault(x => x.Subject.Name == "tenant");
string tenantId = SubdomainRoute.GetSubdomain(context.Request.Host.Value);
if (tenantClaim != null)
{
if (tenantId != tenantClaim.Value)
{
context.RejectIdentity();
return Task.FromResult<int>(0);
}
}
else
{
if (!string.IsNullOrEmpty(tenantId)) // we're trying to access audm.local from x.audm.local
{
context.RejectIdentity();
return Task.FromResult<int>(0);
}
}
return base.ValidateIdentity(context);
}
现在我甚至还有一层额外的安全保障,因此用户无法在租户和#34;之间跳跃。