How can I make accessing my custom IPrincipal easier in ASP.NET MVC?

前端 未结 6 1244
失恋的感觉
失恋的感觉 2021-02-14 23:18

I\'ve written a custom principal object which contains a few additional fields (email and userid in addition to the username).

In order to access these properties I have

6条回答
  •  礼貌的吻别
    2021-02-15 00:03

    I whipped something together quickly. One possible way of easily introducing a custom IPrincipal in ASP.NET MVC is the following:

    1) Create your own descendant of the IPrincipal interface.

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

    2) Let's assume you are using the ASP.NET Membership provider to authenticate your users. Let's quickly build an IMyPrincipal implementation which utilizes the membership API.

    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) Create your own base class type for your controllers. Hide the inherited User member and introduce your own IPrincipal descendant.

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

    4) Have all your controllers descend from this new BaseController type.

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

    5) Create your own controller factory to make sure your principal is introduced on the 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) Register the controller factory in the Global.asax's Application_Start() event handler.

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

    Voila, now you can use the new User (IMyPrincipal) anywhere in your controllers.

    For example:

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

提交回复
热议问题