我认为ASP.NET的身份认证的最核心部分其实就是HttpContext.User这个属性所指向的对象。为了更好了理解Forms身份认证,我认为自己重新实现User这个对象的接口会有较好的帮助。
实现自定义的身份认证标识
前面演示了最简单的ASP.NET Forms身份认证的实现方法,即:直接调用SetAuthCookie方法。不过调用这个方法,只能传递一个登录名。但是有时候为了方便后续的请求处理,还需要保存一些与登录名相关的额外信息。虽然知道ASP.NET使用Cookie来保存登录名状态信息,我们也可以直接将前面所说的额外信息直接保存在Cookie中,但是考虑安全性,我们还需要设计一些加密方法,而且还需要考虑这些额外信息保存在哪里才能方便使用,并还要考虑随登录与注销同步修改。因此,实现这些操作还是有点繁琐的。
为了保存与登录名相关的额外的用户信息,我认为实现自定义的身份认证标识(HttpContext.User实例)是个容易的解决方法。
理解这个方法也会让我们对Forms身份认证有着更清楚地认识。
这个方法的核心是(分为二个子过程):
1. 在登录时,创建自定义的FormsAuthenticationTicket对象,它包含了用户信息。
2. 加密FormsAuthenticationTicket对象。
3. 创建登录Cookie,它将包含FormsAuthenticationTicket对象加密后的结果。
4. 在管线的早期阶段,读取登录Cookie,如果有,则解密。
5. 从解密后的FormsAuthenticationTicket对象中还原我们保存的用户信息。
6. 设置HttpContext.User为我们自定义的对象。
现在,我们还是来看一下HttpContext.User这个属性的定义:
- // 为当前 HTTP 请求获取或设置安全信息。
- //
- // 返回结果:
- // 当前 HTTP 请求的安全信息。
- public IPrincipal User { get; set; }
由于这个属性只是个接口类型,因此,我们也可以自己实现这个接口。
考虑到更好的通用性:不同的项目可能要求接受不同的用户信息类型。所以,我定义了一个泛型类。
- public class MyFormsPrincipal<TUserData> : IPrincipal
- where TUserData : class, new()
- {
- private IIdentity _identity;
- private TUserData _userData;
- public MyFormsPrincipal(FormsAuthenticationTicket ticket, TUserData userData)
- {
- if( ticket == null )
- throw new ArgumentNullException("ticket");
- if( userData == null )
- throw new ArgumentNullException("userData");
- _identity = new FormsIdentity(ticket);
- _userData = userData;
- }
- public TUserData UserData
- {
- get { return _userData; }
- }
- public IIdentity Identity
- {
- get { return _identity; }
- }
- public bool IsInRole(string role)
- {
- // 把判断用户组的操作留给UserData去实现。
- IPrincipal principal = _userData as IPrincipal;
- if( principal == null )
- throw new NotImplementedException();
- else
- return principal.IsInRole(role);
- }
与