【问题标题】:Accessing HttpContext and User Identity from data layer从数据层访问 HttpContext 和用户身份
【发布时间】:2015-04-17 20:06:08
【问题描述】:

我需要在所有其他实体继承自 (Fluent Nhibernate) 的基础实体上实现 AdditionalBy/ChangedBy 类型字段。

从我的存储库/数据层访问HttpContext.User.Identity 可能不是一个好主意.. 是吗? 获取我的用户(当前身份)信息以记录谁添加或更改了记录的最佳方式是什么? 重构整个应用程序以在存储库调用中包含用户信息是愚蠢的。我确信有更好、更通用的方法。

【问题讨论】:

  • 如果您尝试从数据层访问 UserManager,听起来您会遇到循环依赖。走很长的路并在每次创建/更新时填写 By 属性将是最好的选择。

标签: c# asp.net-mvc asp.net-identity httpcontext


【解决方案1】:

从数据层访问 HttpContext 会使生活变得更加困难,特别是如果您使用单元测试。解决方案是创建一个服务来提供应用程序范围的用户信息,例如:

public interface ICurrentUserService {
   string UserName {get;}
   string UserId {get;}
   string HostIP {get;}
   // etc.
}

然后您可以实现具体服务并使用您的 首选 IoC 容器。

public class CurrentWebUserService : ICurrentUserService {
    // implement interface members 
    public CurrentWebUserService(HttpContext context) { ... }

    public string UserName { get { ... } } 
    // etc.
}

// maybe you want a stub service to inject while unit testing.
public class CurrentUserServiceStub : ICurrentUserService {

}

// data layer
public class MyDaoService {
    public DaoService(ICurrentUserService currentUser) { ... }
}

【讨论】:

  • 我一直在尝试将这一切放在一起时遇到问题:1) 在我的 Web 项目中创建一个具有所需用户属性的接口/类。 2) 从数据层访问这些属性 但是,类在什么时候被注入数据?
【解决方案2】:

你是对的。从存储库中引用 HttpContext.User.Identity 类不是一个好主意。 HttpContext 是一个 UI 问题,因此,不应超出 UI 层。

您应该做的是利用 IoC 容器(例如 StructureMap)将您的依赖项 (HttpContext.User.Identity) 详细信息注入您的存储库,或通过依赖项注入任何其他层(例如服务层)。

有关如何设置它的示例(在本例中是会话对象),请参阅this answer 的后半部分。

【讨论】:

  • 我是否正确理解这建议即使使用依赖注入也可以使用会话?
  • 是的,没错。您应该始终致力于针对接口而不是实现进行编程。因此,不是直接针对您的HttpContext.Current.Session 对象(或在您的情况下为HttpContext.User.Identity)进行编程,而是针对在您的应用程序的composite root 中构建的抽象进行编程。当诸如 ASP.NET MVC 5 之类的更改出现在它们更改 HttpContext 对象的位置时,您必须在一个地方而不是在整个应用程序中进行更改。
【解决方案3】:

HttpContext.Current 是一个静态成员,您可以在应用程序的任何位置访问它。 https://msdn.microsoft.com/en-us/library/system.web.httpcontext.current%28v=vs.110%29.aspx 显然有问题,比如调用代码的时候没有HttpContext。

所以 HttpContext.Current.User 应该适合你。我不会推荐它,因为您的底层数据访问代码现在取决于应该保留在您的显示或控制器逻辑等中的内容。此外,这假设您的数据访问是在 Web 应用程序本身中,而不是,比如说,一个外部库。

就个人而言,我只是在添加和修改数据库调用中传递重要的细节,例如用户 ID 和访问时间。制作一个“AuditTrail”类或其他东西。这样您就可以在另一个项目中重用该数据访问代码(总是一件好事),而无需提取所有 HttpContext 内容。

【讨论】:

  • 在所有存储库中传递用户凭据意味着进行大量代码重构。我正在研究其他人目前建议但我还不太了解的 IoC 容器解决方案。
  • 是的,它确实涉及大量重构,尽管在开发过程中规范发生变化时会发生这种情况。 IoC 不是我很了解的东西。希望您无论如何都不必重写所有内容。
【解决方案4】:

AddedBy/ChangedBy 字段在任何数据后端都可能很重要。您甚至可能希望 AccessedBy 用于记录目的。因此,您可能会认为用户信息是数据的核心部分。出于安全原因,您还可能希望记录其他详细信息,例如记录客户端的 IP 地址。将整个上下文传递到数据层可能是一个好主意,这样您就可以灵活地捕获和保存客户端信息。

【讨论】:

  • 感谢您的评论,但您没有回答如何以及最好的方法是什么。谢谢!
【解决方案5】:

我使用工厂来获取正确的 repo,无论是否使用“CurrentUser”,因为有时您需要知道用户是谁,而有时您不需要。

//I have a current user that I got from the Identity
var repo = RepoFactory.GetRepo<Users>(currentUserId);

//I don't have a current user
var repo = RepoFactory.GetRepo<Users>()

通过这种方式,您可以从 HttpContext 中提取身份并仅将您需要的详细信息传递给 repo。

【讨论】:

  • 有趣的解决方案,但它会导致我进行大量代码重构。
【解决方案6】:
  1. HttpContext.User.Identity 属于 System.Security.Principal.IIdentity 类型。不要将它与 Microsoft.AspNet.Identity 库(NuGet 包)混淆,它实际上是由您的问题中的 asp.net-identity 标记所指向的。

  2. 身份库由公共部分及其 ORM 实现组成。通常用于实体框架。但是,如果您打算按照您在 NHibernate 中描述的方式使用Microsoft.AspNet.Identity 包,那么您很可能需要this package

我没有使用它,但是我使用了 EF 实现。请参阅this answer 如何继承预定义的IdentityDbContext&lt;T&gt;,其中 T 是您的 User 类。我猜,NH 有类似的流畅配置。然后您可以将DbContext 中的任何实体链接到AppUser

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2011-09-06
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 2016-01-01
    相关资源
    最近更新 更多