如何在ASP.NET MVC中更轻松地访问我的自定义IPrincipal?

我编写了一个自定义主体对象,其中包含一些额外的字段(除了用户名之外的电子邮件和用户ID)。

为了访问这些属性,我必须将Context.User对象转换为我的自定义主体。

@Html.GetGravitarImage((User as CustomPrincipal).Email) 

通过我的global.ascx中的Application_AuthenticateRequest创建/反序列化此自定义主体。 您可以在此处查看此问题以获取更多信息。

 private void Application_AuthenticateRequest(Object source, EventArgs e) { var application = (HttpApplication)source; var context = application.Context; // Get the authentication cookie string cookieName = FormsAuthentication.FormsCookieName; HttpCookie authCookie = context.Request.Cookies[cookieName]; if (authCookie == null) return; var authTicket = FormsAuthentication.Decrypt(authCookie.Value); context.User = CustomPrincipal.CreatePrincipalFromCookieData(authTicket.UserData); } 

但是,如果用户未经过身份validation,那么我对CustomPrincipal的强制转换将失败(因为它不会在上面的方法中注入),并且(User as CustomPrincipal)的结果将返回null,从而给我一个空引用上面我的方法尝试获取电子邮件时的exception。

什么是这个问题的干净解决方案? 我想让访问我的自定义主体变得容易,并且必须执行以下操作似乎很麻烦:

 @Html.GetGravitarIcon((User is CustomPrincipal) ? (User as CustomPrincipal).Email : "Default Email") 

这是处理这种情况的唯一方法吗?

我很快就把东西扯到了一起。 在ASP.NET MVC中轻松引入自定义IPrincipal的一种可能方法如下:

1)创建自己的IPrincipal接口后代。

 public interface IMyPrincipal : IPrincipal { Guid UserId { get; } string EmailAddress { get; } } 

2)假设您使用ASP.NET成员资格提供程序来validation您的用户。 让我们快速构建一个利用成员资格API的IMyPrincipal实现。

 public class MyPrincipal : IMyPrincipal { private MembershipUser _user; public MyPrincipal() { this._user = Membership.GetUser(); var userName = this._user != null ? this._user.UserName : String.Empty; this.Identity = new GenericIdentity(userName); } public Guid UserId { get { return this._user != null ? (Guid) this._user.ProviderUserKey : default(Guid); } } public string EmailAddress { get { return this._user != null ? this._user.Email : null; } } public IIdentity Identity { get; private set; } public bool IsInRole(string role) { return false; } } 

3)为控制器创建自己的基类类型。 隐藏inheritance的用户成员并介绍您自己的IPrincipal后代。

 public class BaseController : Controller { protected virtual new MyPrincipal User { get { return HttpContext.User as MyPrincipal; } } } 

4)让所有控制器都从这个新的BaseController类型下降。

 public class HomeController : BaseController { //... } 

5)创建自己的控制器工厂,以确保在HttpContext / Thread上引入了主体。

 public class MyControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance (RequestContext requestContext, Type controllerType) { try { var controller = base.GetControllerInstance(requestContext, controllerType); requestContext.HttpContext.User = Thread.CurrentPrincipal = new MyPrincipal(); return controller; } catch (Exception) { return base.GetControllerInstance(requestContext, controllerType); } } } 

6)在Global.asax的Application_Start()事件处理程序中注册控制器工厂。

 var controllerFactory = new MyControllerFactory(); ControllerBuilder.Current.SetControllerFactory(controllerFactory); 

瞧,现在您可以在控制器的任何位置使用新用户(IMyPrincipal)。

例如:

 public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewBag.UserId = User.UserId; ViewBag.UserName = User.EmailAddress; return View(); } 

您可以使用“new”关键字创建基类并覆盖“User”属性,也可以创建如下的扩展方法:

 public static class ControllerExtensions { public static CustomPrincipal CustomPrincipal(this Controller controller) { if(controller.User is CustomPrincipal) { return controller.User as CustomPrincipal; } return null; // maybe return an empty object instead to get around null reference... } } 

使用ASP.NET MVC在Razor页面中访问IPrincipal实现的最佳方法是执行以下操作:

  1. 实现System.Security.Principal.IPrincipal接口。
  2. 实现System.Security.Principal.IIdentity接口。
  3. Global.asax定义一个方法: void Application_AuthenticateRequest(Object, EventArgs) ,它持久保存IPrincipalIIdentity两个实现。
  4. IPrincipal创建扩展方法以公开您的IIdentity实现。
  5. 最后,在 web.config文件中添加先前扩展方法的命名空间。

最后,您将能够访问IIdentity的自定义实现,而不是类型转换。 您现在可以像这样访问自定义实现

 Hello @User.CustomIdentity().FirstName @User.CustomerIdentity().LastName! 

这些步骤简明扼要地描述了这里写的详细文章: http : //rizzo7.blogspot.com/2012/04/mvc-30-razor-custom-principal-and.html

您可以创建某种实用方法或向您的某个服务添加方法,以检查它是否是您的自定义主体。 也许是这样的:

 public class UserService : IUserService { public CustomPrincipal CurrentUser { get { CustomPrincipal user = HttpContext.Current.User as CustomPrincipal; if (user == null) return GuestUser; // Just some default user object return user; } } } 

您也可以使用与John Kalberer的答案相同的方式为Email和UserID制作扩展方法:

 public static class CustomPrincipalExtensions { public static string Email(this CustomPrincipal cUser) { return cUser != null ? cUser.Email : "Default Email" } public static string UserID(this CustomPrincipal cUser) { return cUser != null ? cUser.UserID : "Default ID" } } 

未经授权时,您可以使用默认值将用户对象设置为自定义主体的特定实例:

 if (authCookie == null) { context.User = CustomPrincipal.Default; // Or CreateDefault() return; }