设计选择
假设两个 ASP.NET MVC 授权/角色设计故事。两者都旨在最大限度地减少对中间层或数据存储的命中:
- 从数据库中获取“MyRoleProvider”信息后,随后将其存储在 AuthTicket 用户数据中,这反过来意味着 auth-cookie 包含角色信息。此外,在这个故事中,存储和检索此角色信息是由一个完全在“MyRoleProvider”之外的不同实现完成的。
或者...
- 从数据库中获取“MyRoleProvider”信息后,随后将其存储在会话中并从那里访问。更准确地说,“MyRoleProvider”类本身将尽可能在内部访问(和更新)会话。
同样,上述两个故事都旨在通过“缓存”角色信息来最大限度地减少访问外部存储的延迟。两者都工作正常。问题是,两种设计故事选择是否同样有效?如果不是,为什么?
问题
任何地方似乎都没有说明“最佳实践”,它说“您的(自定义)RoleProvider 应该始终知道角色信息的位置,无论是在会话、缓存、数据库等中。”
此外,任何地方似乎都没有(可靠的)指导来解释您不应该将哪些类型的东西存储在authCookie的“ userData ”中。那里的少量文档和指导仅表明两件事:
- 'userData' 可以存储额外的用户信息(一种模糊、广泛的陈述)。我只在网上看到过一个代码示例,其中涉及存储额外的第 3 方身份/身份验证信息。
- 不要在“userData”中放入太多数据,因为这可能会使 cookie 变得太大而无法传输(某些浏览器会限制 cookie 大小)。
而已。从上述指导中,没有人被明确告知“将 userData 仅限于身份验证信息是最佳实践。” 而且我当然没有看到一个文件说“将授权或角色信息放入'userData'是一个坏主意,因为......”
推导出最佳实践?
我自己对两种设计选择相同的回答是“不”。我想提出我的论点,并在以下情况下向您学习:
- 你同意。
- 你不同意,因为我在大惊小怪。
- 你不同意;尽管我的论点是有效的,但对于为什么我的想法最终是错误的,还有更好的论点。
希望最佳实践概念能够作为答案出现。现在我的论点...
我的论点
我认为应该采用第二个设计故事,因为它代表了更好的模块化:角色信息完全在“MyRoleProvider”内部处理。第一个选项不必要地混合了身份验证(从 cookie 中提取身份)和授权问题。事实上,所有内置的 ASP.NET 安全机制都将这两个主题分开;基本 ASP.NET 功能从不将角色信息存储在 authcookie 中。如果有人想确认这一点,请尝试反映这些类:FormsAuthenticationModule、FormsAuthentication、带有 RolePrincipal 实现的 IPrincipal 和带有 FormsIdentity 实现的 IIdentity。
ASP.NET RolePrincipal 值得特别强调。它允许角色信息确实存储在 cookie 中,但它是与 auth-cookie 分开的第二个 cookie。此外,这个特殊的习惯用法仍然涉及与 RoleProvider 的协商。请参阅此 MSDN 文档的示例部分。
进一步研究 RolePrincipal,让我们看看 RolePrincipal.IsInRole()。尽管任何此类 IPrincipal 派生类都以编程方式结合了身份和角色信息,但内部实现仍将 RoleProvider 作为角色信息的唯一来源(请注意对 的引用Roles.RoleProviders...
):
public bool IsInRole(string role)
{
if (this._Identity != null)
{
if (!this._Identity.IsAuthenticated || role == null)
{
return false;
}
else
{
role = role.Trim();
if (!this.IsRoleListCached)
{
this._Roles.Clear();
string[] rolesForUser = Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name);
string[] strArrays = rolesForUser;
for (int i = 0; i < (int)strArrays.Length; i++)
{
string str = strArrays[i];
if (this._Roles[str] == null)
{
this._Roles.Add(str, string.Empty);
}
}
this._IsRoleListCached = true;
this._CachedListChanged = true;
}
return this._Roles[role] != null;
}
}
else
{
throw new ProviderException(SR.GetString("Role_Principal_not_fully_constructed"));
}
}
这种 ASP.NET 对角色信息在哪里找到的“一站式”深度假设,就是为什么应该将角色信息合并到 RoleProvider 中。简而言之,我声称:
- 如果您确实将角色信息存储在 cookie 中,那么 ASP.NET 没有将其组合到 auth-cookie 的内置功能的原因正是因为 ASP.NET 在不同的提供者之间保持了强烈的关注点分离。
- 任何 RoleProvider 都应该知道在哪里可以找到角色信息,无论是在 cookie、会话还是其他地方。
结论:
不要将角色信息放入 auth-cookie,并确保您的(自定义)RoleProvider知道找到角色信息的所有位置,无论是数据库、Web 服务、会话、缓存还是 cookie。
同意?不同意?想法?