Search code examples
c#asp.netasp.net-mvc-5asp.net-identity-2

Identity 2.0 User Identity is null in MVC 5 controller initializer


I have an MVC 5 project using Asp.Net Identity 2.0. I am also using a generic repository pattern. As part of the database schema I have fields for various tables which store the user id of the inserting/updating/deleting user. Therefore I would like to pass the user object, or user id at least to the generic repository to be used when modifying records.

However, as i was unable to access the identity directly in the repository class I am attempting to pass it on repository instantiation. It looks like this:

using System.Data.Entity;
using System.Threading.Tasks;
using System.Net;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using My.Models;

namespace My.Controllers
{
    [Authorize]
    public class FooController : MasterController
    {
        private IGenericRepositoryAsync<Topic> _repository;

        public FooController()
        {
            //Point A
            _repository = new GenericRepositoryAsync<Foo>(User.Identity);
        }


        public async Foo<ActionResult> Index()
        {
            //POINT B
            //_repository = new GenericRepositoryAsync<Foo>(User.Identity);
            return View(await _repository.GetAllAsync());
        }
    }
}

As an authorized user at "Point A" User.Identity is null, at //Point B it is not null but I don't want to have to put the repository initializer in every controller Action.

Your help and feedback is appreciated.


Solution

  • Web Api solution

    You may create your on Authorize filter class and then add the userId into Request properties collection:

    public class MyAuthorizeAttribute : AuthorizeAttribute 
    {
        public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()) return;
    
            base.OnAuthorization(actionContext);
    
            Guid userId;
    
            if (actionContext.RequestContext.Principal.Identity.IsAuthenticated
                && Guid.TryParse(actionContext.RequestContext.Principal.Identity.GetUserId(), out userId))
            {
                actionContext.Request.Properties.Add("userId", actionContext.RequestContext.Principal.Identity.GetUserId());
            }
        }
    }
    

    Once the class exists, you have to add this filter on Application Startup class (Global.asax web_start, Startup.cs) like this:

    config.Filters.Add(new MyAuthorizeAttribute());
    

    For Owin Startup.cs will be something like this:

    public void Configuration(IAppBuilder app)
    {
        ConfigureOAuth(app);
    
        HttpConfiguration config = new HttpConfiguration();
        WebApiConfig.Register(config);
        config.Filters.Add(new MyAuthorizeAttribute());
    }
    

    Then, in your controller you will be able to get the userId jus doing:

    Guid userId = (Guid) ActionContext.Request.Properties["userId"];
    

    MVC Solution

    For MVC use directly on Controller:

    using Microsoft.AspNet.Identity;
    
    ...
    
    User.Identity.GetUserId();
    

    Or add a filter as in Web Api solution:

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        ...
        Guid userId = filterContext.HttpContext.User.Identity.Name.GetUserId();
        ...
    }