3

我希望能够访问经过身份验证的用户(如 UserId 和 FirstName)的自定义属性,而无需每次都查询数据库。我通过 Stack Overflow 上的一篇文章找到了这个站点,我喜欢这种方法 - 但我使用 IoC / 存储库并决定不尝试让 global.asax 与数据库通信,因为担心它与存储库模式不兼容。

相反,我创建了一个到 CustomPrincipal 的接口,并使用 IoC (Castle) 创建一个实例并将其传递给控制器​​(随后传递给我的基本控制器)。

基本控制器使用我在 CustomPrincipal 中创建的方法来完成博客作者在 global.asax 中提出的相同任务。即,CustomPrincipal 从数据库或缓存中初始化并分配给 HttpContext.Current.User。

然后我的控制器/视图可以引用如下属性...

((ICustomPrincipal)(HttpContext.Current.User)).FirstName;

它有效,但我感觉到一些代码气味。首先也是最重要的,如果我从控制器中引用 HttpContext 我已经杀死了我的单元测试。我正在考虑修改我的 CustomPrincipal 对象以返回上述值(这样我就可以在我的单元测试中模拟它),但我想知道这是否是一种解决方法而不是一个好的解决方案。

我会以正确的方式解决这个问题吗?我可以做一些小的调整来使它成为一个强大的解决方案,还是我应该从头开始使用 FormsAuthenticationTicket 或类似的东西?

谢谢!

4

2 回答 2

7

我想抛出一个替代想法,以便寻找此信息的人可以有一些选择。

我去寻找一个可行的 FormsAuthenticationTicket 示例,发现NerdDinner在不影响单元测试的情况下添加自定义属性做得相当不错。

在我的例子中,我修改了我的 LogOn 例程(我已经在我的单元测试中模拟了它)来创建一个 FormsAuthenticationTicket。NerdDinner 加密票证并将其添加为 cookie,但我也可以像原始提案一样将加密票证添加到缓存中。我还用代表我所有自定义属性的 JSON 序列化对象替换了单个 UserData 属性。

CustomIdentityDTO dto = new CustomIdentityDTO { 
   UserId = userId, FirstName = firstName, LastName = lastName };
JavaScriptSerializer serializer = new JavaScriptSerializer();

FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
  1, // version
  username,
  DateTime.Now, // creation
  DateTime.Now.AddMinutes(30), // expiration
  false, // not persistent
  serializer.Serialize(dto));

string encTicket = FormsAuthentication.Encrypt(authTicket);
//HttpContext.Current.Response.Cookies.Add(...)
HttpContext.Current.Cache.Add(username, encTicket, ...

然后我通过 PostAuthenticateRequest 处理程序在 global.asax 中检索加密票证(来自缓存或 cookie),这很像 NerdDinner(用于 cookie)或博主的提议(用于缓存)。

NerdDinner 实现 IIdentity 而不是 IPrincipal。代码中对自定义字段的引用如下:

((CustomIdentity)Page.User.Identity).FirstName // from partial view

((CustomIdentity)User.Identity).FirstName // from controller

使用这两种方法后,我发现 NerdDinner 的方法效果很好。切换后我没有遇到太多障碍。

于 2010-09-22T13:47:31.703 回答
2

创建一个 ICustomPrincipalManager 接口怎么样?

public interface ICustomPrincipalManager 
{
    ICustomPrincipal Current {get;}
}

它可以由访问 HttpContext、数据库、缓存或其他任何内容的类实现,但您也可以模拟接口以进行单元测试。您的控制器将使用 IoC 框架来获取您的 ICustomPrincipalManager,然后访问如下信息:

_customPrincipalManager.Current.FirstName
于 2010-09-21T18:26:32.687 回答