2011-08-12 15 views
9

He escrito un objeto principal personalizado que contiene algunos campos adicionales (correo electrónico y ID de usuario además del nombre de usuario).¿Cómo puedo hacer que acceder a mi IPrincipal personalizado sea más fácil en ASP.NET MVC?

Para acceder a estas propiedades tengo que convertir el objeto Context.User como mi principal personalizado.

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

Este principal personalizada se crea/deserializado a través de la Application_AuthenticateRequest en mi global.ascx. Puede ver esta pregunta que le pedí al here para más información.

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

Sin embargo, si un usuario no está autenticado, entonces mi yeso para CustomPrincipal fallará (porque no se inyectará en el método anterior) y el resultado de la (User como CustomPrincipal) devolverá nulo , por lo tanto, me da una excepción de referencia nula cuando mi método anterior intenta obtener el correo electrónico.

¿Cuál sería una solución limpia a este problema? Quiero hacer que el acceso a mi director de aduana fácil y tener que hacer lo siguiente parece engorroso:

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

Es esta la única manera de manejar esta situación?

Respuesta

2

Usted podría crear una clase base y reemplazar la propiedad "usuario" por medio de la "nueva" palabra clave o crear un método de extensión de esta manera:

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

Simplemente me podría ser, pero me parece extensión métodos molestos para cosas comunes, a menos que estén definidos en un espacio de nombres común. No puedes simplemente presionar Ctrl-. para incluirlo automáticamente como es normal en Visual Studio. –

+0

Personalmente los amo, pero creo que cada uno es suyo. Esto podría colocarse en el espacio de nombres System.Web.Mvc o algo así para que siempre se recoja. –

+0

Estoy tratando de entender esto en este momento y no entiendo qué es MyUserClass. ¿Podría explicar por favor? – LukeP

0

Se puede crear algún tipo de método de utilidad o añadir una método a uno de sus servicios que verifica si es su principal personalizado. Tal vez algo como:

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

También puede hacer que los métodos de extensión para el correo electrónico y el ID de usuario de la misma manera como la respuesta de John 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

Cuando no está autorizado, se podría establecer el objeto de usuario a una instancia específica del principal personalizado con valores predeterminados:

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

Arreglé algo rápidamente. Una forma posible de introducir fácilmente un IPrincipal personalizado en ASP.NET MVC es la siguiente:

1) Cree su propio descendiente de la interfaz IPrincipal.

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

2) Supongamos que usted está utilizando el proveedor de pertenencia ASP.NET para autenticar a los usuarios. Construyamos rápidamente una implementación IMyPrincipal que utilice la API de membresía.

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) Cree su propio tipo de clase base para sus controladores. Oculte el miembro heredado del usuario e introduzca su propio descendiente IPrincipal.

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

4) Todos sus controladores descienden de este nuevo tipo de BaseController.

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

5) Cree su propia fábrica de controladores para asegurarse de que su principal se introduce en 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) registra la fábrica de controlador en el controlador de eventos de Global.asax Application_Start().

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

Voila, ahora puedes utilizar el nuevo usuario (IMyPrincipal) en cualquier parte de los controladores.

Por ejemplo:

public ActionResult Index() 
{ 
    ViewBag.Message = "Welcome to ASP.NET MVC!"; 

    ViewBag.UserId = User.UserId; 
    ViewBag.UserName = User.EmailAddress; 

    return View(); 
} 
1

La mejor manera de hacer que su aplicación IPrincipal accesibles en las páginas de la maquinilla de afeitar utilizando ASP.NET MVC, está haciendo lo siguiente:

  1. implementar la interfaz System.Security.Principal.IPrincipal.
  2. Implemente la interfaz System.Security.Principal.IIdentity.
  3. En Global.asax defina un método para: void Application_AuthenticateRequest(Object, EventArgs) que persista en sus dos implementaciones de IPrincipal y .
  4. Cree un método de extensión para IPrincipal para exponer su implementación de IIdentity.
  5. Finalmente, agregue el espacio de nombres para el método de extensión anterior en su archivo web.config en <system.web.webPages.razor>.

Al final, usted será capaz de acceder a su implementación personalizada de IIdentity en lugar de la conversión de tipos. Ahora puede acceder a su implementación personalizada así:

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

Estos pasos son una descripción concisa y breve de un artículo bien escrito detallado aquí: http://rizzo7.blogspot.com/2012/04/mvc-30-razor-custom-principal-and.html

Cuestiones relacionadas