【问题标题】:Persist User Data in ASP.NET MVC在 ASP.NET MVC 中持久化用户数据
【发布时间】:2012-05-15 05:59:23
【问题描述】:

以前有人问过类似的问题,但我仍然没有答案,我花了相当多的时间试图找到一个。

场景是这样的。我们有一个使用表单身份验证/LINQ-to-SQL 数据模型的 ASP.NET MVC 应用程序。

每个用户可以与 1 个或多个帐户相关联。登录后,应用程序会检查它们关联的帐户数量。

0 = 转到错误页面,让他们知道他们无权访问
1 = 设置 用户数据 以使用该页面帐户
2 个或更多 = 转到允许他们选择要使用的帐户的页面(可以在访问期间更改)

您将如何存储这些信息?

此外,我想将此帐户用作我的控制器操作的基础。即他们访问的后续页面上的数据将与他们选择的帐户相关。

想到了单例咳嗽,但不确定如何实现。

我目前正在研究的一种方法是一个基本控制器,所有控制器都将从该控制器继承

  1. 检查用户是否登录。
  2. 如果是,请检查他们是否选择了帐户
    • 否 - 将他们重定向到帐户选择页面
    • 是 - 继续原始请求

推荐/最佳实践方法是什么?

谢谢 马尔科

【问题讨论】:

  • 为什么不在 Cookie 中,即使在 URL 中也可以使用 queryString AccountID=DGI36F2。您标记了会话状态,因此即使使用会话。 I'm guessing you know these things back-to-front but can you give us a heads up which direction you want this question going?

标签: c# asp.net-mvc session-state


【解决方案1】:

不要使用基本控制器。您可以使用操作过滤器完成此操作。这将为您提供拦截点,以检查他们是否已登录,是否选择了帐户,甚至将他们重定向到错误或帐户选择页面。您所要做的就是在操作过滤器的OnActionExecuting 方法中设置filterContext.Result,以防止请求通过。在操作期间,您可以完全访问会话、临时数据、cookie 和整个 HttpContext,就像在控制器中一样。您还可以使用过滤器属性过滤器提供程序属性注入依赖项,这样就可以为您提供所需的任何数据访问权限。

就数据建模而言,我对 Linq to SQL 不太熟悉,但我认为普通的一对多应该可以解决问题:

User (1) <-------> (0..*) Account

public class User
{
    public virtual ICollection<Account> Accounts { get; protected internal set; }
}

public class Account
{
    public int UserId { get; protected internal set; }
    public virtual User User { get; protected internal set; }
}

更新:抱歉,我误解了您所说的“商店”的含义。在 MVC 中,只有几种方法可以存储它 - Session、Cookie 和 Cache(以及 TempData,它只是短期会话)是最流行的选择。我的选择将取决于。 Session 可能是最简单的,但是如果你部署到一个带有负载均衡器的服务器场,你需要考虑如果用户的 session 跳过物理机会发生什么。会话会保持不变吗?

正如 Jeremy 所说,还有 cookie。这里不用担心负载平衡,但语义比会话更难处理。例如,您必须先发送重定向以写入 cookie,然后才能读取它,而且我从不喜欢您必须添加过期 cookie 才能删除它的事实。由于这些数据是您安全的一部分,您可能还想加密 cookie 值。

如果您使用缓存,则数据很可能最终仍会存在于内存中的某个位置,例如会话(除非您使用的是 SQL 会话提供程序)。缓存可能是我最后的选择,因为我们使用 Azure,而且它们的缓存不支持很多出色的 MVC 功能。您也有同样的问题,负载均衡器将用户移动到集群中的另一台机器,数据可能需要重新缓存。

无论哪种方式,您仍应为此使用操作过滤器,而不是基本 Controller 类。

【讨论】:

  • 感谢您的回答@danludwig。我正在寻找有关如何/在何处存储这些附加用户数据的实际实现,并且一些代码示例会有所帮助。作为我的 L2S 课程的一部分,我已经拥有用户和帐户之间的一对多模型。所以我不确定的部分是存储所选帐户,在确保安全的同时在后续请求中读取它。
  • +1 对操作过滤器的良好呼吁。这是我经常忽略的 MVC 的一个特性。
  • 现在我已经为我们的 IoC 容器提供了一个很好的 FilterAttributeFilterProvider,我将过滤器用于各种事情。使控制器更精简,非常适合像 OP 中提到的那样横切关注点。
【解决方案2】:

你说的是什么类型的秤?我们说的是一百万用户还是几千?

我的第一个想法是创建一个字典,键是登录用户名(假设它是唯一的),值是关联帐户的数组(键或所有数据)。然后我会将字典放入缓存中。每当创建新关联时,它就会过期。

这种方法存在几个问题。首先,新协会的创建速度有多快?如果它们不断被创建,那么缓存是一个有争议的问题。你总是要去数据库。其次,如果您有数百万用户/关联,将它们全部放入缓存可能不切实际。

另一种可能性是会话状态服务器,它专门用于存储关系。

另一种可能性是每次都查询数据库,这取决于数据集的大小。当数据集增长到无法每次提取实时数据的规模时,您可以构建一个适合您需求的解决方案。

至于在请求之间持久化选定的帐户,选项可以是 cookie、url 或数据库(可以是用户上的一个字段,即 CurrentAccount,这种方法有点笨拙)。

由于您使用的是 MVC,因此我将使用 URL、路由和自定义路由约束,您可以创建一个包含帐户的 url。由于用户必须登录,因此您已经知道用户身份。

示例:http://www.acme.com/{account}/edit/

检查用户是否登录可以在 Global.asax 中的操作过滤器或 Application_AuthenticateRequest 中处理。身份验证在 ASP.NET 中实现得相当好。哎呀,很多都是由 web.config 中的配置值驱动的。

在确认身份验证后,可以使用相同的方法进行帐户重定向。或者您可以等待并签入操作过滤器。

【讨论】:

  • L2S 是否使用动态代理?由于这些原因,我们在尝试在 Session 中存储(分离)实体时遇到了问题。实际的运行时类型是通过反射创建的,并且对于它们运行的​​机器来说是唯一的。因此,如果我们在 Session 中存储了一个(动态代理)实体,那么其中一个用户的请求被路由到集群中的另一台机器,另一台机器无法对其进行反序列化,因为它具有不同的动态代理类名称。此处的字典解决方案是一种选择,但您可能希望在将实体数据放入基于内存的存储之前将其 DTO 为具体的非实体类型。
  • @danludwig 我从未使用过 L2S。我在 nhibernate 中遇到了与动态代理相同的问题。有时我想知道这些好处是否值得头痛。 DTO 肯定是一种选择。
  • URL 参数方法不会造成特权安全风险的巨大升级吗?在用户以自己身份进行身份验证后,更改 URL 以访问其他用户的数据或访问其角色通常允许的管理或更高权限功能是微不足道的。通常,URL 令牌也是有风险的,因为即使使用 HTTPS,URL 也会暴露给任何中间人攻击者。
  • @pwdst 如果您只使用网址,那么是的,这是一个巨大的漏洞。事实上,任何时候状态存储在客户端都有被泄露的风险。
猜你喜欢
  • 1970-01-01
  • 2013-02-21
  • 1970-01-01
  • 1970-01-01
  • 2012-02-10
  • 2010-11-01
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多