I have an application that uses Identity 2.0 with Owin.
I want the application to seed a default user and log in automatically while on development (I'm wrapping the method and its call with #if DEBUG
condition).
I tried adding the following method to IdentityConfig.csApplicationUserManager.Create
method , but after calling it, HttpContext.Current.User
is still null at the next call.
private void SeedAndLoginDefaultUser()
{
var user = this.FindByName("***");
if (user == null)
this.Create(new ApplicationUser { /* ... */ }, "***");
using (var signInManager = new ApplicationSignInManager(this,
HttpContext.Current.GetOwinContext().Authentication))
signInManager.PasswordSignIn(user.UserName, "***", true, false);
}
But it keeps on authenticating the user over and over. I'm sure there should be a more appropriate location to perform this automation.
P.S. doing it from the Global.asax.cs or Startup.cs is impossible, since owin isn't initialized yet at that stage.
I tried adding it in the the Context initializer, the user gets created, but the login fails.
on this answer:
Actually the UserManager is anyway overridden in the IdentityConfig.cs class. But what I'm thinking is, your solution will check for user existence each time a method attributed under CustomAuthorize
is called. Whereas I only want to perform the default user creation and login only at app startup.
In my database initializer I have some crucial seed tables, that has data related to user, which means, I have to create the user in the seed method. So my question is now, when I create a user manually as the following code:
public class Initializer : DropCreateDatabaseAlways<ApplicationDbContext>
{
private static volatile bool processing;
protected override void Seed(ApplicationDbContext context)
{
if (processing)
return;
processing = true;
using (var um = ApplicationUserManager.Get())
{
var shimmy = new ApplicationUser
{
//Id = Guid.NewGuid().ToString(),
FirstName = "Shimmy",
LastName = "Weitzhandler",
UserName = "***",
Email = "***",
//EmailConfirmed = true,
};
var task = um.CreateAsync(shimmy, "***");
task.Wait();
var result = task.Result;
if (result.Succeeded)
{
using (var sm = ApplicationSignInManager.Get())
{
var siTask = sm.SignInAsync(shimmy, true, true);
siTask.Wait();
if (siTask.Exception != null)
{
throw siTask.Exception;
}
}
}
else
{
throw new InvalidOperationException();
}
}
//seed my tables
processing = false;
}
}
As you can see I even added a static member to avoid looping back the initializer, but I believe it still doesn't help.
Because when I'm trying to create the user manually (adding to the Users
table, using the UserManager.PasswordHasher
, I then can't log in to the account.
But the problem with the code above is that I'm calling it from the Seed
, and I suspect it calls itself back internally when I try to create a user, then it gets stuck.
The resolution I'm looking for is how to create a user manually and be able to login to that account. I'm probably missing some point in the password hashing / user verification / whatever else.
You need to this before the default Autorization starts. To do this the easiest way is to create your own AuthorizeAttribute.
public class MyCustomAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
#if DEBUG
return true;
#else
return base.AuthorizeCore(httpContext);
}
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
#if DEBUG
// CHANGE TO YOUR USER MANAGER
var userManger = filterContext.HttpContext.GetOwinContext().GetUserManager<ApplicationUser>();
var user = userManger.FindByName("***");
if (user == null)
this.Create(new ApplicationUser {/* ... */}, "***");
using(var signInManager = new ApplicationSignInManager(userManger, filterContext.HttpContext.GetOwinContext().Authentication))
signInManager.PasswordSignIn(user.UserName, "***", true, false);
return;
#endif
return base.OnAuthorization(filterContext);
}
}
And then replace all existing Authorize attributes with your own, i.e.
[MyCustomAuthorize]
[MyCustomAuthorize(Roles = "ROLENAME")]
Solution 2:
If don't want do signin for each request, you can skip that but you still need to fetch the user from DB. Implement your service to getUser. Otherwise you can just hard code a user with a name and a role (if necessary).
public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
{
#if DEBUG
// CHANGE TO YOUR USER MANAGER
var user = GETUSER("");
var principal = new GenericPrincipal(new GenericIdentity(user.Name), new[] { user.RoleName });
Thread.CurrentPrincipal = principal;
HttpContext.Current.User = principal;
return;
#endif
return base.OnAuthorization(filterContext);
}