I trying to add custom properties to the ApplicationUser for a web site using MVC5 and OWIN authentication. I\'ve read https://stackoverflow.com/a/10524305/264607 and I like ho
You're getting an exception because HttpContext.Current.User.Identity.IsAuthenticated
returns false at the point of check (so does HttpContext.Current.Request.IsAuthenticated
).
If you remove the if (HttpContext.Current.User.Identity.IsAuthenticated)
statement it will work fine (at least this part of code).
I've tried a simple thing like this:
BaseController.cs
public abstract class BaseController : Controller
{
protected virtual new CustomPrincipal User
{
get { return HttpContext.User as CustomPrincipal; }
}
}
CustomPrincipal.cs
public class CustomPrincipal : IPrincipal
{
public IIdentity Identity { get; private set; }
public bool IsInRole(string role) { return false; }
public CustomPrincipal(string username)
{
this.Identity = new GenericIdentity(username);
}
public DateTime BirthDate { get; set; }
public string InvitationCode { get; set; }
public int PatientNumber { get; set; }
}
Global.asax.cs
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
CustomPrincipal customUser = new CustomPrincipal(User.Identity.Name);
customUser.BirthDate = DateTime.Now;
customUser.InvitationCode = "1234567890A";
customUser.PatientNumber = 100;
HttpContext.Current.User = customUser;
}
HomeController.cs
public ActionResult Index()
{
ViewBag.BirthDate = User.BirthDate;
ViewBag.InvitationCode = User.InvitationCode;
ViewBag.PatientNumber = User.PatientNumber;
return View();
}
And this is working fine. So unless this code:
userManager = new UserManager(new UserStore(new ApplicationDbContext()));
ApplicationUser user = userManager.FindByName(HttpContext.Current.User.Identity.Name);
is not returning a valid (custom) user object, the problem is with the if()
statement.
Your update looks fine, and if you're happy to store data as claims in a cookie you can go with it, although I personally hate the try {}
catch block there.
What I do instead is this:
BaseController.cs
[AuthorizeEx]
public abstract partial class BaseController : Controller
{
public IOwinContext OwinContext
{
get { return HttpContext.GetOwinContext(); }
}
public new ClaimsPrincipal User
{
get { return base.User as ClaimsPrincipal; }
}
public WorkContext WorkContext { get; set; }
}
I decorate the base controller class with a custom attribute.
AuthorizeExAttribute.cs:
public class AuthorizeExAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
Ensure.Argument.NotNull(filterContext);
base.OnAuthorization(filterContext);
IPrincipal user = filterContext.HttpContext.User;
if (user.Identity.IsAuthenticated)
{
var ctrl = filterContext.Controller as BaseController;
ctrl.WorkContext = new WorkContext(user.Identity.Name);
}
}
}
And WorkContext.cs:
public class WorkContext
{
private string _email;
private Lazy currentUser;
private IAuthenticationService authService;
private ICacheManager cacheManager;
public User CurrentUser
{
get
{
var cachedUser = cacheManager.Get(Constants.CacheUserKeyPrefix + this._email);
if (cachedUser != null)
{
return cachedUser;
}
else
{
var user = currentUser.Value;
cacheManager.Set(Constants.CacheUserKeyPrefix + this._email, user, 30);
return user;
}
}
}
public WorkContext(string email)
{
Ensure.Argument.NotNullOrEmpty(email);
this._email = email;
this.authService = DependencyResolver.Current.GetService();
this.cacheManager = DependencyResolver.Current.GetService();
this.currentUser = new Lazy(() => authService.GetUserByEmail(email));
}
I then access the WorkContext like this:
public class DashboardController : BaseController
{
public ActionResult Index()
{
ViewBag.User = WorkContext.CurrentUser;
return View();
}
}
I'm using Ninject's Dependency Resolver to resolve authService
and cacheManager
but you can skip caching and replace authService with ASP.NET Identity UserManager
I believe.
I also wanted to give credit where it's due as the WorkContext class is heavily inspired by NugetGallery project.