Asp Net Mvc Identity Multitenancy FindByEmailAsync not working - asp.net-mvc

I'm trying to implements a multitenancy application following step by step the Scott Brady post here:
https://www.scottbrady91.com/ASPNET-Identity/Quick-and-Easy-ASPNET-Identity-Multitenancy
I'm not really sure where I should put these code lines:
var context = new ApplicationUserDbContext<ApplicationUser>("DefaultConnection");
var userStore = new ApplicationUserStore<ApplicationUser>(context) { TenantId = 1 };
var userManager = new UserManager<ApplicationUser, string>(userStore);
I have tried to use this into my login action in AccountController:
var context = new ApplicationDbContext();
var userStore = new ApplicationUserStore<ApplicationUser>(context) { TenantId = tenantId };
UserManager = new ApplicationUserManager(userStore);
SignInManager.UserManager = UserManager;
ApplicationUser userApp =await UserManager.FindByEmailAsync(model.Email);
But UserManager.FindByEmailAsync always returns null, any idea of what I should do to get this working? My real objetive is to SingIn User but always return Failure. And I think the problem is finding the ApplicationUser.
If you need additional information please, let me know, thanks in advance.

Your are Using the Classes directly. Give a try with this way...and make sure that you have the user with that gmail that you are providing.
var context = new ApplicationDbContext();
var store = new UserStore<ApplicationUser>(context);
var manager = new ApplicationUserManager(store);
ApplicationUser userApp=await manager.FindByEmailAsync(model.Email);

Related

PasswordSignInAsync and CreateAsync without Entity Framework

SignInManager.PasswordSignInAsync checks user if present in database and signs in. await UserManager.CreateAsync creates new user in database. await SignInManager.SignInAsync signs in the user.
Correct me if I'm wrong but it trivial for this question. How to implement those functionalities when we are not using Entity Framework in ASP.NET MVC?
You need not to implement those method even if you're not using EF
You can rely to asp.net identity by registering a custom class with a IUserStore and call them to use your own database access
I've followed this article and the membership works even with my own written data access layer:
https://markjohnson.io/articles/asp-net-core-identity-without-entity-framework/
Basically you have to :
write your db access (of course)
create a model for the user (and for the role, etc.)
create a UserStore that implements IUserStore, handling YourCustomModel methods
add the UserStore as a service in app's Startup
You can then refer to identity managers in your Controller thanks to dependency injection
private readonly UserManager<YourCustomModel> _userManager;
private readonly SignInManager<YourCustomModel> _signInManager;
public YourCustomController(
UserManager<YourCustomModel> userManager,
SignInManager<YourCustomModel> signInManager
)
{
_userManager = userManager;
_signInManager = signInManager;
}
and in your actions use them to invoke identity methods :
var uModel = YourCustomModel.Static.SelectByEmail(vModel.Email);
var result = await _signInManager.PasswordSignInAsync(uModel, vModel.Password,
vModel.RememberMe, lockoutOnFailure: false);
if (result.Succeeded) ...
SignInAsync method instead and create a user object in memory.
var userPrincipal = await _signInManager.CreateUserPrincipalAsync(new
ApplicationUser
{
Id = 1,
UserName = viewModel.UserName,
Email = viewModel.UserName,
SecurityStamp = Guid.NewGuid().ToString()
});
foreach(var claim in userPrincipal.Claims)
{
appUser.Claims.Add(new ApplicationUserClaim { UserId = appUser.Id,
ClaimType = claim.Type, ClaimValue = claim.Value });
}
await _signInManager.SignInAsync(appUser, viewModel.RememberMe);

How do I seed Users and Roles in MVC6

I've started in Visual Studio with a new project > ASP NET 5 > Web Application and then followed the initial tutorial here:
https://docs.asp.net/projects/mvc/en/latest/getting-started/first-mvc-app/index.html
One of the tasks I've been struggling with is seeding the database with Users, Roles, and then assigning the Roles to the Users.
This answer, or variations of it look fruitful:
https://stackoverflow.com/a/20521530/2591770
But this code:
var store = new UserStore<ApplicationUser>(context);
var manager = new UserManager<ApplicationUser>(store);
var user = new ApplicationUser {UserName = "founder"};
Results in an immediate error.
CS7036 There is no argument given that corresponds to the required formal parameter 'optionsAccessor' of 'UserManager.UserManager(IUserStore, IOptions, IPasswordHasher, IEnumerable>, IEnumerable>, ILookupNormalizer, IdentityErrorDescriber, IServiceProvider, ILogger>, IHttpContextAccessor)'
Is this a change in the framework or is it likely I've omitted something elsewhere?
I can null the rest of the parameters but can't help feeling that I've missed something.
var userManager = new UserManager<ApplicationUser>(userStore,null,null,null,null,null,null,null,null,null);
This is how I did it.
public class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService<ApplicationDbContext>();
var userManager = serviceProvider.GetService<UserManager<ApplicationUser>>();
and then in the Configure method of Startup.cs:
SeedData.Initialize(app.ApplicationServices);
Edit1:
var user0 = new ApplicationUser { UserName = "bob", Email = "bob#asd.com" };
var result = userManager.CreateAsync(user0, "Password1!").Result;

Get the user id of a username identity 2.0

MVC 5 with asp.net identity 2.0
I understand how to get the currently logged in user id. I have a need to get the user id of a different user in the system. How is this done?
Ex. I need to get the user id of user names "fsmith" ...
Inside the AccountController you can call the following method to get user object and then get the User Id.
var user = await UserManager.FindByNameAsync(userName);
var userId = user.Id;
If you are not inside AccountController you can get the UserManager reference using the following code
var UserManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
To add to Shashi's useful answer...
If you're inside the account controller you can use the existing UserManager:
var user = await UserManager.FindByNameAsync(userName);
var userId = user.Id;
In other controllers (and maybe select other places where HttpContext is available) you create a User Manager with:
var um = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
But what it took me a while to realize is you can get at it just about anywhere with this last bit. For instance I used it in my seed method (in Configuration.cs) so I could seed the User property of another model:
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(*insert-your-db-context-here*));
One way would to use the FindByNameAsync method of your user manager (or the generic version of it). It takes the name of the user (in your case "fsmith") and returns a task of a user object. This user object contains all the information available about that user.
A code snippet could look similar to the following one (if you're looking for the database ID):
var user = await UserManager.FindByNameAsync("fsmith");
var userId = user.Id;
EDIT
The UserManager instance is normally declared as follows (keep in mind that there are many ways of declaring it, for example when using Dependency Injection):
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
If you are using Bearing Token Auth, the above sample do not return an Application User.
Instead, use this:
ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);
return user.Id;
This works in apsnetcore 2.0. Have not tried in earlier versions.

Update User Claim not Taking Effect. Why?

I am using ASP.NET MVC 5.1 with Owin and Claims authentication.
After the user changes its email I need to update the users claims, so I tried in the controller:
ClaimsIdentity identity = (ClaimsIdentity)User.Identity;
Claim claim = identity.FindFirst(ClaimTypes.Email);
identity.RemoveClaim(claim);
identity.AddClaim(new Claim(ClaimTypes.Email, newEmail));
IOwinContext context = new OwinContext();
context.Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
context.Authentication.SignIn(identity);
The Claim is changed but when I refresh the page the email claims is the original again ...
It seems the cookie is not being updated. Any idea what I am doing wrong?
And is it possible to get the value of "IsPersistent" from the identity so when I sign it again I will have the same value?
Thank You,
Miguel
I had this same problem, so just wanted to summarise my findings here. As Chris says, the basis of the answer is indeed here: How to change authentication cookies after changing UserName of current user with asp.net identity but I found that thread a bit hard to follow, and that question isn't really a direct duplicate.
To begin, get the AuthenticationManager from the current OWIN context. Once you have that, you can get the value of "isPersistent" (and other properties from the original SignIn call), by calling the AuthenticateAsync method. Then to update the claims of the current user identity you just need to replace the value of the AuthenticationResponseGrant property like this:
var identity = (ClaimsIdentity)User.Identity;
// Call AddClaim, AddClaims or RemoveClaim on the user identity.
IOwinContext context = Request.GetOwinContext();
var authenticationContext =
await context.Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalCookie);
if (authenticationContext != null)
{
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
identity,
authenticationContext.Properties);
}
It is the final setting of the AuthenticationResponseGrant property that actually updates the cookie.
Hope this helps other readers.
SORRY, this is an ASP.NET CORE solution
I also challenged the problem with claims, but the answer was easy to find.
To refresh your cookie, you can rely on the RefreshSignInAsync() function of the SignInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ApplicationDbContext _context;
private readonly SignInManager<ApplicationUser> _signInManager;
public ApiClubController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, ApplicationDbContext context)
{
_userManager = userManager;
_context = context;
_signInManager = signInManager;
}
Inside your function:
//GET CURRENT USER
var usr = await GetCurrentUserAsync();
//OLD CLAIM
var myClaims = await _userManager.GetClaimsAsync(usr);
var oldClaim = myClaims.Where(o => o.Type.Equals("Club")).FirstOrDefault();
if (oldClaim != null)
{
await _userManager.RemoveClaimAsync(usr, oldClaim);
}
//CREATE CLUB CLAIM
var clubClaim = new Claim("Club", "" + id);
await _userManager.AddClaimAsync(usr, clubClaim);
//RESET USER COOKIE
await _signInManager.RefreshSignInAsync(usr);
//RETURN
return Ok(company);;
NOTE:
I'm using an API here, because I'm mixing up a lot with angular.
If you update your identity with your API, you need to refresh your page in order to view things based on your claim
This works for me. Not sure if it is the best way but the updated claim is in the DB and in subsequent controllers.
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
var c = identity.Claims.FirstOrDefault(r => r.Type == "tId");
await UserManager.RemoveClaimAsync(user.Id, c);
await UserManager.AddClaimAsync(user.Id, new Claim("tId", "9032C945-DC5C-4FC9-BE7C-8EDC83A72E58"));
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, identity);

Updating user data - ASP.NET Identity

I've added custom fields to the ApplicationUser class
I've also created a form through which the user can enter/edit the fields.
However for some reason I'm not able to update the fields in the database.
[HttpPost]
[ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(EditProfileViewModel model)
{
if (ModelState.IsValid)
{
// Get the current application user
var user = User.Identity.GetApplicationUser();
// Update the details
user.Name = new Name { First = model.FirstName, Last = model.LastName, Nickname = model.NickName };
user.Birthday = model.Birthdate;
// This is the part that doesn't work
var result = await UserManager.UpdateAsync(user);
// However, it always succeeds inspite of not updating the database
if (!result.Succeeded)
{
AddErrors(result);
}
}
return RedirectToAction("Manage");
}
My problem is similar to MVC5 ApplicationUser custom properties, but that seems to use an older version of Identity because the IdentityManager class doesn't seem to exist.
Can someone guide me on how to update User info in the database?
UPDATE:
If I include all the fields in the register form, all the values are stored in the appropriate field in a new record of the Users table from the database.
I don't know to make changes to the fields of an existing user (row in the users table). UserManager.UpdateAsync(user) doesn't work.
Also note my issue is more Identity oriented than EntityFramework
OK... I spent hours trying to figure why userManager.updateAsync would not persist the user data that we edit ... until I reached the following conclusion:
The confusion arises from the fact that we create the UserManager in one line like this:
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDbContext()));
...then we use manager.UpdateAsync( user ); but that will update the user in the context, and then we will need to save changes to the dbcontext of the Identity. So, the question is how to get the Identity DBcontext in the easiest way.
To solve this, we should not create the UserManager in one line ... and here is how I do it:
var store = new UserStore<ApplicationUser>(new MyDbContext());
var manager = new UserManager(store);
then after updating the user by calling
manager.UpdateAsync(user);
then you go to the context
var ctx = store.context;
then
ctx.saveChanges();
wahooooooo...persisted :)
Hope this will help someone who pulled their hair for a few hours :P
If you leave any of the fields for ApplicationUser OR IdentityUser null the update will come back as successful but wont save the data in the database.
Example solution:
ApplicationUser model = UserManager.FindById(User.Identity.GetUserId())
Add the newly updated fields:
model.Email = AppUserViewModel.Email;
model.FName = AppUserViewModel.FName;
model.LName = AppUserViewModel.LName;
model.DOB = AppUserViewModel.DOB;
model.Gender = AppUserViewModel.Gender;
Call UpdateAsync
IdentityResult result = await UserManager.UpdateAsync(model);
I have tested this and it works.
The OWIN context allows you to get the db context. Seems to be working fine so far me, and after all, I got the idea from the ApplciationUserManager class which does the same thing.
internal void UpdateEmail(HttpContext context, string userName, string email)
{
var manager = context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindByName(userName);
user.Email = email;
user.EmailConfirmed = false;
manager.Update(user);
context.GetOwinContext().Get<ApplicationDbContext>().SaveChanges();
}
The UserManager did not work, and As #Kevin Junghans wrote,
UpdateAsync just commits the update to the context, you still need to save the context for it to commit to the database
Here is quick solution (prior to new features in ASP.net identity v2) I used in a web forms projetc. The
class AspNetUser :IdentityUser
Was migrated from SqlServerMembership aspnet_Users. And the context is defined:
public partial class MyContext : IdentityDbContext<AspNetUser>
I apologize for the reflection and synchronous code--if you put this in an async method, use await for the async calls and remove the Tasks and Wait()s. The arg, props, contains the names of properties to update.
public static void UpdateAspNetUser(AspNetUser user, string[] props)
{
MyContext context = new MyContext();
UserStore<AspNetUser> store = new UserStore<AspNetUser>(context);
Task<AspNetUser> cUser = store.FindByIdAsync(user.Id);
cUser.Wait();
AspNetUser oldUser = cUser.Result;
foreach (var prop in props)
{
PropertyInfo pi = typeof(AspNetUser).GetProperty(prop);
var val = pi.GetValue(user);
pi.SetValue(oldUser, val);
}
Task task = store.UpdateAsync(oldUser);
task.Wait();
context.SaveChanges();
}
I also had problems using UpdateAsync when developing a version of SimpleSecurity that uses ASP.NET Identity. For example, I added a feature to do a password reset that needed to add a password reset token to the user information. At first I tried using UpdateAsync and it got the same results as you did. I ended up wrapping the user entity in a repository pattern and got it to work. You can look at the SimpleSecurity project for an example. After working with ASP.NET Identity more (documentation is still non-existent) I think that UpdateAsync just commits the update to the context, you still need to save the context for it to commit to the database.
I have tried the functionality in the same way and when i call UserManager.Updateasync method it succeeds but there is no update in the database. After spending some time i found another solution to update the data in aspnetusers table which is following:
1) you need to create UserDbContext class inheriting from IdentityDbContext class like this:
public class UserDbContext:IdentityDbContext<UserInfo>
{
public UserDbContext():
base("DefaultConnection")
{
this.Configuration.ProxyCreationEnabled = false;
}
}
2) then in Account controller update user information like this:
UserDbContext userDbContext = new UserDbContext();
userDbContext.Entry(user).State = System.Data.Entity.EntityState.Modified;
await userDbContext.SaveChangesAsync();
where user is your updated entity.
hope this will help you.
Excellent!!!
IdentityResult result = await UserManager.UpdateAsync(user);
Based on your question and also noted in comment.
Can someone guide me on how to update User info in the database?
Yes, the code is correct for updating any ApplicationUser to the database.
IdentityResult result = await UserManager.UpdateAsync(user);
Check for constrains of all field's required values
Check for UserManager is created using ApplicationUser.
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
This works for me. I'm using Identity 2.0, it looks like GetApplicationUser isn't there anymore.
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (!string.IsNullOrEmpty(form["FirstName"]))
{
user.FirstName = form["FirstName"];
}
if (!string.IsNullOrEmpty(form["LastName"]))
{
user.LastName = form["LastName"];
}
IdentityResult result = await UserManager.UpdateAsync(user);
I am using the new EF & Identity Core and I have the same issue, with the addition that I've got this error:
The instance of entity type cannot be tracked because another instance
of this type with the same key is already being tracked.
With the new DI model I added the constructor's Controller the context to the DB.
I tried to see what are the conflict with _conext.ChangeTracker.Entries() and adding AsNoTracking() to my calls without success.
I only need to change the state of my object (in this case Identity)
_context.Entry(user).State = EntityState.Modified;
var result = await _userManager.UpdateAsync(user);
And worked without create another store or object and mapping.
I hope someone else is useful my two cents.
Add the following code to your Startup.Auth.cs file under the static constructor:
UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
The UserManagerFactory setting line of code is what you use to associate your custom DataContext with the UserManager. Once you have done that, then you can get an instance of the UserManager in your ApiController and the UserManager.UpdateAsync(user) method will work because it is using your DataContext to save the extra properties you've added to your custom application user.
I am using .Net Core 3.1 or higher version.Please follow the solution:
public class UpdateAssignUserRole
{
public string username { get; set; }
public string rolename { get; set; }
public bool IsEdit { get; set; }
}
private async Task UpdateSeedUsers(UserManager<IdentityUser> userManager, UpdateAssignUserRole updateassignUsername)
{
IList<Users> Users = await FindByUserName(updateassignUsername.username);
if (await userManager.FindByNameAsync(updateassignUsername.username) != null)
{
var user = new IdentityUser
{
UserName = updateassignUsername.username,
Email = Users[0].Email,
};
var result = await userManager.FindByNameAsync(updateassignUsername.username);
if (result != null)
{
IdentityResult deletionResult = await userManager.RemoveFromRolesAsync(result, await userManager.GetRolesAsync(result));
if (deletionResult != null)
{
await userManager.AddToRoleAsync(result, updateassignUsername.rolename);
}
}
}
}

Resources