2011-08-12 44 views
9

我写了一个自定义主体对象,其中包含一些额外的字段(电子邮件和用户名除外)。如何在ASP.NET MVC中更轻松地访问我的自定义IPrincipal?

为了访问这些属性,我必须将Context.User对象作为我的自定义主体进行投射。

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

此自定义主体通过我的global.ascx中的Application_AuthenticateRequest创建/反序列化。你可以看到我询问here的这个问题了解更多信息。

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); 
} 

但是,如果用户没有通过验证,那么我投来CustomPrincipal将失败,(用户为CustomPrincipal)的结果(因为它不会在上面的方法注入)将返回null ,当我上面的方法试图获得电子邮件时,给我一个空引用异常。

什么是这个问题的干净解决方案?我要让我的访问自定义主体轻松,不必做以下似乎繁琐:

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

这是处理这种情况的唯一途径?

回答

2

你既可以创建一个基类,并使用了“新”的关键字,或创建一个扩展方法,这样覆盖“用户”属性:

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... 
    } 
} 
+0

这可能只是我,但我发现扩展方法讨厌常见的东西,除非它们是在一个通用的命名空间中定义的。你不能只点击Ctrl-。在Visual Studio中自动包含它。 –

+0

我个人很喜欢它们,但每个都是属于我自己的。这可以放在System.Web.Mvc命名空间或其他东西中,所以它总是被拾取。 –

+0

我试图让我的头在此刻,我不明白MyUserClass是什么。你能解释一下吗? – LukeP

0

你可以建立某种形式的实用工具方法或添加方法到您的服务之一,检查它是否是您的自定义主体。也许是这样的:

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; 
     } 
    } 
} 
0

你也可以做的电子邮件和用户名扩展方法相同的方式约翰Kalberer的回答是:

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" 
    } 
} 
0

如果没有授权,你可以在用户对象设置为具有默认值的自定义主体的特定实例:

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

我快速地将东西揉在一起。在ASP.NET MVC中轻松引入自定义IPrincipal的一种可能方式如下:

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

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

2)假设您使用ASP.NET成员资格提供程序对用户进行身份验证。让我们快速构建一个利用成员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)为您的控制器创建您自己的基类类型。隐藏继承的用户成员并引入您自己的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(); 
} 
1

,让您IPrincipal实施使用ASP.NET MVC你的剃须刀的网页访问的最好办法,是做如下:

  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文件<system.web.webPages.razor>中添加上一个扩展方法的名称空间。

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

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

这些步骤是一个很好详细的文章的简洁和简短描述写在这里:http://rizzo7.blogspot.com/2012/04/mvc-30-razor-custom-principal-and.html

相关问题