ASP.NET MVC - Set custom IIdentity or IPrincipal

后端 未结 9 1497
忘了有多久
忘了有多久 2020-11-21 23:06

I need to do something fairly simple: in my ASP.NET MVC application, I want to set a custom IIdentity / IPrincipal. Whichever is easier / more suitable. I want to extend the

9条回答
  •  余生分开走
    2020-11-21 23:45

    Here's how I do it.

    I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal.

    1. Create the interface

      interface ICustomPrincipal : IPrincipal
      {
          int Id { get; set; }
          string FirstName { get; set; }
          string LastName { get; set; }
      }
      
    2. CustomPrincipal

      public class CustomPrincipal : ICustomPrincipal
      {
          public IIdentity Identity { get; private set; }
          public bool IsInRole(string role) { return false; }
      
          public CustomPrincipal(string email)
          {
              this.Identity = new GenericIdentity(email);
          }
      
          public int Id { get; set; }
          public string FirstName { get; set; }
          public string LastName { get; set; }
      }
      
    3. CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.

      public class CustomPrincipalSerializeModel
      {
          public int Id { get; set; }
          public string FirstName { get; set; }
          public string LastName { get; set; }
      }
      
    4. LogIn method - setting up a cookie with custom information

      if (Membership.ValidateUser(viewModel.Email, viewModel.Password))
      {
          var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First();
      
          CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
          serializeModel.Id = user.Id;
          serializeModel.FirstName = user.FirstName;
          serializeModel.LastName = user.LastName;
      
          JavaScriptSerializer serializer = new JavaScriptSerializer();
      
          string userData = serializer.Serialize(serializeModel);
      
          FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
                   1,
                   viewModel.Email,
                   DateTime.Now,
                   DateTime.Now.AddMinutes(15),
                   false,
                   userData);
      
          string encTicket = FormsAuthentication.Encrypt(authTicket);
          HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
          Response.Cookies.Add(faCookie);
      
          return RedirectToAction("Index", "Home");
      }
      
    5. Global.asax.cs - Reading cookie and replacing HttpContext.User object, this is done by overriding PostAuthenticateRequest

      protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
      {
          HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
      
          if (authCookie != null)
          {
              FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
      
              JavaScriptSerializer serializer = new JavaScriptSerializer();
      
              CustomPrincipalSerializeModel serializeModel = serializer.Deserialize(authTicket.UserData);
      
              CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
              newUser.Id = serializeModel.Id;
              newUser.FirstName = serializeModel.FirstName;
              newUser.LastName = serializeModel.LastName;
      
              HttpContext.Current.User = newUser;
          }
      }
      
    6. Access in Razor views

      @((User as CustomPrincipal).Id)
      @((User as CustomPrincipal).FirstName)
      @((User as CustomPrincipal).LastName)
      

    and in code:

        (User as CustomPrincipal).Id
        (User as CustomPrincipal).FirstName
        (User as CustomPrincipal).LastName
    

    I think the code is self-explanatory. If it isn't, let me know.

    Additionally to make the access even easier you can create a base controller and override the returned User object (HttpContext.User):

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

    and then, for each controller:

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

    which will allow you to access custom fields in code like this:

    User.Id
    User.FirstName
    User.LastName
    

    But this will not work inside views. For that you would need to create a custom WebViewPage implementation:

    public abstract class BaseViewPage : WebViewPage
    {
        public virtual new CustomPrincipal User
        {
            get { return base.User as CustomPrincipal; }
        }
    }
    
    public abstract class BaseViewPage : WebViewPage
    {
        public virtual new CustomPrincipal User
        {
            get { return base.User as CustomPrincipal; }
        }
    }
    

    Make it a default page type in Views/web.config:

    
      
        
        
        
        
      
    
    

    and in views, you can access it like this:

    @User.FirstName
    @User.LastName
    

提交回复
热议问题