如何在单独的程序集中获取用户标识
我正在开发一个有两个项目的应用程序:
- 核心 – 使用存储库模式和域驱动设计来容纳数据访问层
-
UI – 使用ASP.Net MVC。 目前,我能够通过User属性在UI控制器内获取当前登录用户的信息(id,name等),如下所示:
using Microsoft.AspNet.Identity; public class ExamController : Controller { IExaminationRepository _repository; public ExamController() { _repository = RepositoryFactory.Get(); } [HttpPost] [Authorize(Roles = "Examiner")] public ActionResult Create(ExamViewModel viewModel) { try { ExaminationDomain domain = Mapper.Map(viewModel); //TODO: Move this to the repository domain.AuthorId = User.Identity.GetUserId(); _repository.Add(domain); return RedirectToAction("Index"); } catch { return View(); } } }
我想移动这一行: domain.AuthorId = User.Identity.GetUserId();
到我的存储库具体实现如下:
using Microsoft.AspNet.Identity; using System.Security.Principal; internal class ExaminationRepository { public DBEntities context; public IPrincipal User; public ExaminationRepository(DBEntities context) { this.context = context; //I'd like to instantiate User property here: this.User = "not sure what to instantiate with"; } public void Add(ExaminationDomain domain) { Examination newExam = Mapper.Map(domain); newExam.AuthorId = User.Identity.GetUserId(); newExam.CreatedBy = User.Identity.Name; newExam.CreatedDate = DateTime.Now; context.Examinations.Add(newExam); context.SaveChanges(); }
但我不确定在构造函数中实例化User属性的内容。 我已经阅读了一些建议来使用WindowsIdentity.GetCurrent().User
而不是创建用户属性,但这不包含用户ID,只包含用户名。
有关获取用户信息的任何其他建议?
我真的很感激这方面的一些帮助..
谢谢,
我会使用自定义管理器将您的存储库与httpcontext分离。 例如,我有一个名为IAUthenticationManager的接口
public interface IAUthenticationManager { string CurrentUserId(); bool HasCurrentUserRole(string roleName), }
易于测试和完全分离。
这将无法轻松工作,因为存储库可以在许多不同的上下文中使用,甚至是未设置用户的上下文。 如果在构造函数中创建具体依赖项,则存储库将不再是独立的数据提供程序。
例如,引用
HttpContext.Current.User.Identity
直接将创建对Web上下文的依赖,并且存储库在非Web上下文中将不可用。
您可以做的最好的事情就是让存储库客户端提供:
public void Add(ExaminationDomain domain, IPrincipal principal) { Examination newExam = Mapper.Map(domain); newExam.AuthorId = principal.Identity.GetUserId(); newExam.CreatedBy = principal.Identity.Name; newExam.CreatedDate = DateTime.Now; context.Examinations.Add(newExam); context.SaveChanges(); }
或(可能)
public ExaminationRepository(DBEntities context, IPrincipal user) { this.context = context; this.user = user; }
如果告诉容器如何解决依赖关系,后一种情况仍可由IoC容器正确解析。
在Web上下文中,您可以设置容器以将其解析为HttpContext.Current.User
。 在非Web上下文中,您可以设置容器以将其解析为WindowsIdentity.GetCurrent().User
。
使用HttpContext类是一个单例类:首先添加一个使用到Microsoft.AspNet.Identity; 然后你可以做这样的事情:
HttpContext.Current.User.Identity.GetUserId();
由于GetUserId是一种扩展方法,因此您可以引用Microsoft.AspNet.Identity
但是如果你需要访问你应用程序的几个地方的用户信息,我建议你有一个包含你需要的属性的包装类,并在用户登录时实例化,然后将它存储在会话变量中,这样你就有两个好处:
1-您不需要查询数据库以获取用户名,电子邮件等..整个应用程序的每个用户信息使用情况。
2-您不需要将存储库存放到aspnet标识的程序集。
您需要使用当前线程的标识信息来实例化this.User:
this.User = System.Threading.Thread.CurrentPrincipal; var currentIdentity = (System.Security.Claims.ClaimsIdentity)User.Identity; var userId = currentIdentity.Claims .Where(p => p.Type.EndsWith("nameidentifier")).Single().Value;
请注意,CurrentPrincipal.Identity的类型是IIdentity。 您可以将其强制转换为System.Security.Claims.ClaimsIdentity,其中包含名为Claims的属性。 此属性包含您的所有声明,包括用户ID和第三方令牌(例如Facebook令牌)。
要检索UserId,请找到Type ==“ http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier ”的声明