我希望能够访问经过身份验证的用户(如UserId和FirstName)的自定义属性,而无需每次都查询数据库。我通过Stack Overflow上的帖子找到了this site,我喜欢这种方法 - 但我使用IoC /存储库并决定不尝试使用global.asax与数据库通信,因为它担心它与存储库不兼容图案。
相反,我创建了一个CustomPrincipal接口,我使用IoC(Castle)创建一个实例并将其传递给控制器(以及随后传递给我的基本控制器)。
基本控制器使用我在CustomPrincipal中创建的方法来实现博客作者在global.asax中处理的相同任务。即,CustomPrincipal从数据库或缓存初始化并分配给HttpContext.Current.User。
我的控制器/视图可以按如下方式引用属性...
((ICustomPrincipal)(HttpContext.Current.User)).FirstName;
它有效,但我感觉到一些代码味道。首先,如果我从控制器引用HttpContext,我已经杀死了我的单元测试。我正在考虑修改我的CustomPrincipal对象以返回上面的值(这样我可以在单元测试中模拟它)但我想知道这是否是一个解决方法而不是一个好的解决方案。
我是以正确的方式来做这件事的吗?我是否可以做一些小的调整以使其成为一个强大的解决方案,还是应该从头开始使用FormsAuthenticationTicket或其他类似的东西?
谢谢!
答案 0 :(得分:7)
我想抛弃一个替代的想法,以便寻找这些信息的人可以有一些选择。
我去寻找一个可行的FormsAuthenticationTicket示例,发现NerdDinner在不影响单元测试的情况下添加自定义属性做得相当不错。
就我而言,我修改了LogOn例程(我在单元测试中已经嘲笑)来创建FormsAuthenticationTicket。 NerdDinner加密票证并将其添加为cookie,但我也可以将加密的票证添加到缓存中,如original proposal。我还用表示所有自定义属性的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的方法非常有效。切换后我没有遇到太多障碍物。
答案 1 :(得分:2)
如何创建ICustomPrincipalManager界面?
public interface ICustomPrincipalManager
{
ICustomPrincipal Current {get;}
}
它可以通过访问HttpContext,数据库,缓存等的类来实现,但您也可以模拟单元测试的接口。您的控制器将使用IoC框架获取您的ICustomPrincipalManager,然后访问以下信息:
_customPrincipalManager.Current.FirstName