5

设计选择

假设两个 ASP.NET MVC 授权/角色设计故事。两者都旨在最大限度地减少对中间层或数据存储的命中:

  • 从数据库中获取“MyRoleProvider”信息后,随后将其存储在 AuthTicket 用户数据中,这反过来意味着 auth-cookie 包含角色信息。此外,在这个故事中,存储和检索此角色信息是由一个完全在“MyRoleProvider”之外的不同实现完成的。

或者...

  • 从数据库中获取“MyRoleProvider”信息后,随后将其存储在会话中并从那里访问。更准确地说,“MyRoleProvider”类本身将尽可能在内部访问(和更新)会话。

同样,上述两个故事都旨在通过“缓存”角色信息来最大限度地减少访问外部存储的延迟。两者都工作正常。问题是,两种设计故事选择是否同样有效?如果不是,为什么?

问题

任何地方似乎都没有说明“最佳实践”,它说“您的(自定义)RoleProvider 应该始终知道角色信息的位置,无论是在会话、缓存、数据库等中。”

此外,任何地方似乎都没有(可靠的)指导来解释您不应该将哪些类型的东西存储在authCookie的“ userData ”中。那里的少量文档和指导仅表明两件事:

  1. 'userData' 可以存储额外的用户信息(一种模糊、广泛的陈述)。我只在网上看到过一个代码示例,其中涉及存储额外的第 3 方身份/身份验证信息。
  2. 不要在“userData”中放入太多数据,因为这可能会使 cookie 变得太大而无法传输(某些浏览器会限制 cookie 大小)。

而已。从上述指导中,没有人被明确告知“将 userData 仅限于身份验证信息是最佳实践。” 而且我当然没有看到一个文件说“将授权或角色信息放入'userData'是一个坏主意,因为......”

推导出最佳实践?

我自己对两种设计选择相同的回答是“不”。我想提出我的论点,并在以下情况下向您学习:

  1. 你同意。
  2. 你不同意,因为我在大惊小怪。
  3. 你不同意;尽管我的论点是有效的,但对于为什么我的想法最终是错误的,还有更好的论点。

希望最佳实践概念能够作为答案出现。现在我的论点...

我的论点

我认为应该采用第二个设计故事,因为它代表了更好的模块化:角色信息完全在“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 中。简而言之,我声称:

  1. 如果您确实将角色信息存储在 cookie 中,那么 ASP.NET 没有将其组合到 auth-cookie 的内置功能的原因正是因为 ASP.NET 在不同的提供者之间保持了强烈的关注点分离。
  2. 任何 RoleProvider 都应该知道在哪里可以找到角色信息,无论是在 cookie、会话还是其他地方。

结论:

不要将角色信息放入 auth-cookie,并确保您的(自定义)RoleProvider知道找到角色信息的所有位置,无论是数据库、Web 服务、会话、缓存还是 cookie。

同意?不同意?想法?

4

2 回答 2

7

有很多不同的关注点和设计选择来决定在哪里实际缓存信息,无论是 cookie、会话还是其他提供者。

当然,第一个问题是你是否应该缓存它。当然,对于不断访问数据库以获取相当静态的信息存在担忧。但是,同样担心能够立即将某人拒之门外。

只有在不需要立即响应的情况下,缓存才会变得可行。因此,没有关于缓存授权的最佳实践。如果您的应用程序不需要那种级别的安全性,当然也没有关于在哪里缓存它的最佳实践。

假设上述不是问题,则需要权衡位置。

Cookie
如果你把它放在一个 cookie 中,那么它可以被捕获并随后被重放。此外,它会略微增加您的互联网流量,因为每次请求都会传输 cookie。

会话
如果你把它放在会话中,那么你要么将自己限制在单个 Web 服务器上,要么必须将会话状态存储在整个 Web 场可访问的位置。如果您采用后一种方法,那么您完全有可能将会话存储在某个数据库中,从而完全破坏了您开始使用会话的理由。

Memcache 或其他
这类似于将角色存储在会话中;但是它通常存储在单独服务器的内存中,并且通常速度很快。缺点是对于负载平衡的网络场,这可能会增加另一个故障点……除非它被正确集群。在这一点上,您增加了项目开发、部署和维护成本......


最终,没有最佳实践。只有一堆非常依赖情况的权衡。坦率地说,对于这种类型的数据,我根本不会缓存它。它通常相对较小,并且对其的查询通常非常快。如果我们谈论的是成千上万的用户,我可能会考虑它,但在那个级别上,还有许多其他操作考虑因素最终会使这里的选择变得显而易见。

于 2012-10-18T19:27:30.817 回答
4

在我看来,你在问一个荒谬的问题。没有人会在身份验证 cookie 中存储角色数据。ASP.NET 并没有这样做,因为它们提供了将其存储在加密的单独 cookie 中的 RolePrincipal。

无论如何,cookie 的整个问题都是毫无意义的,因为这是 RolePrincipal 的实现细节。应用程序不应该知道角色数据的存储位置。

所以我要问你的问题是……我们为什么还要讨论这个问题?你在问最好的做法是做一些与系统如何做相反的事情,然后争论为什么你不应该以这种没人会使用的方式来做。

此外,您关于RoleProvider必须处理 cookie 的评论是不正确的。RoleProvider 不会创建RolePrincipal,这是在框架内完成的。是否使用cookies的选择不在RoleProvider,而是由RoleManagerModule框架类提供,由框架IPrincipal实例化的方式。

中的示例RolePrincipalRoleProvider. 实际上,RoleManagerModule控件是这个功能。 RoleManagerModuleHttpModule安装到 IIS 中并作为管道的一部分运行的。它甚至不知道RoleProvider,基本上这意味着角色是从 cookie 中以非常低的级别填充的,当 `RoleProvider 开始运行时,如果它发现角色已经存在,它什么也不做.

于 2012-10-18T19:40:42.797 回答