I want crud operation for Identity user. When i click on submit button it show me error
ArgumentNullException: Value can not be null.
Parameter name: provider
atMicrosoft.Extensions.DependencyInjection.ServiceProviderExtensions.GetRequiredService[T](IServiceProvider provider)
UserController
public async Task<ActionResult> Edit([Bind("UserName,Id")] ApplicationUser formuser, string id, string RoleId)
{
// ViewBag.RoleId = new SelectList(RoleManager.Roles, "Id", "Name");
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var user = await userManager.FindByNameAsync(formuser.Email);
user.UserName = formuser.UserName;
if (ModelState.IsValid)
{
await userManager.UpdateAsync(user);
return RedirectToAction("Index");
}
else
{
ViewBag.RoleId = new SelectList(RoleManager.Roles, "Id", "Name");
return View();
}
}
Related
How can we access the properties of the ApplicationUser from the Account Controller in. While creating a an ApplicationUser object with User, object reference set to null error occurs.The example code is
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
{
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
return View(nameof(Login));
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded)
{
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
//I want to access the ApplicationUser Properites here
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
ViewData["ReturnUrl"] = returnUrl;
ViewData["LoginProvider"] = info.LoginProvider;
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
}
}
You should be able to access the ApplicationUser like this...
//I want to access the ApplicationUser Properites here
var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
I'm using ASP.NET core identity with EF end I would like to store data related to the user in the authentication cookie.
This is how I used to do with ASP.NET 4.6 (appcontext is the data to store):
public static void IdentitySignin(AppContext appContext, string providerKey = null, bool isPersistent = false)
{
var claims = new List<Claim>();
// create *required* claims
claims.Add(new Claim(ClaimTypes.NameIdentifier, appContext.UserId.ToString()));
claims.Add(new Claim(ClaimTypes.Name, appContext.UserName));
// serialized AppUserState object
claims.Add(new Claim("appcontext" + EZA.Store.AppContext.Version, appContext.ToString()));
var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
// add to user here!
AuthenticationManager.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = isPersistent,
ExpiresUtc = DateTime.UtcNow.AddDays(7),
}, identity);
}
but now I'm using ASP.NET Identity with EF and I can't find a way to store some data in the cookie.
Use AddClaimsAsync or AddClaimAsync of UserManager<YourUserIdentity>. for exemple like this when you sign in your user:
public class AccountController : Controller
{
public UserManager<YourUserIdentity> UserManager { get; private set; }
public SignInManager<YourUserIdentity> SignInManager { get; private set; }
public AccountController(UserManager<YourUserIdentity> userManager,
SignInManager<YourUserIdentity> signInManager)
{
UserManager = userManager;
SignInManager = signInManager;
}
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.UserName);
await UserManager.AddClaimAsync(user, new Claim("your-claim", "your-value"));
var signInStatus = await SignInManager.PasswordSignInAsync(user, model.Password, model.RememberMe, lockoutOnFailure: false);
if (signInStatus.Succeeded)
return RedirectToLocal(returnUrl);
ModelState.AddModelError("", "Invalid username or password.");
return View(model);
}
// If we got this far, something failed, redisplay form
return View("Index", new LoginPageViewModel() { Login = model });
}
}
Before i read #aqua's answer(i have learned this way just now), i would say that you have two options:
1 - Overriding UserClaimsPrincipalFactory like below:
public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public AppClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
((ClaimsIdentity)principal.Identity).AddClaims(new[] {
new Claim("<claim name>", value)
});
return principal;
}
}
// register it
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();
2- Using OnSigningIn event.
services.Configure<IdentityOptions>(opt =>
{
opt.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents()
{
OnSigningIn = async (context) =>
{
ClaimsIdentity identity = (ClaimsIdentity)context.Principal.Identity;
identity.AddClaim(new Claim("<claim name>", value));
}
};
});
I'm having a bit of an issue.
I am finishing work on my first mvc app and I'm using the default Login and Registration Actions.They work, but when I seed the db with initial data I add an administrator user(the user is added to the database correctly). When I try to login as this user - I cannot pass the authentication, I get an error saying "wrong password"
Any help would be strongly appreciated.(I really have no clue)
I am using mvc 5,identity 3.0, entityframework 6.
My account controller actions are
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
// if (ModelState.IsValid){
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning(2, "User account locked out.");
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
// }
// If we got this far, something failed, redisplay form
// return View(model);
}
//
// GET: /Account/Register
[HttpGet]
[AllowAnonymous]
public IActionResult Register()
{
return View();
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser {UserName = model.UserName, Name = model.Name, Email = model.Email,BirthDate = model.BirthDate, LastName = model.Name };
PasswordHasher<ApplicationUser> a = new PasswordHasher<ApplicationUser>();
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{ await_signInManager.SignInAsync(user,isPersistent:false);
await _userManager.AddToRoleAsync(user, "User");
_logger.LogInformation(3, "User created a new account with password.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
And this is my data seed method (with class). it is called in the StartupCS after setting the routing.
public static async void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService<ApplicationDbContext>();
bool need= false;
try
{
if (context.Users.Count() == 0)
need = true;
}
catch (Exception)
{ }
if (need)
{
string[] roles = new string[] { "Administrator", "User" };
foreach (string role in roles)
{
var roleStore = new RoleStore<IdentityRole>(context);
if (!context.Roles.Any(r => r.Name == role))
{
await roleStore.CreateAsync(new IdentityRole(role));
}
}
await context.SaveChangesAsync();
var user = new ApplicationUser
{
Name = "Admin",
LastName = "Admin",
Email = "admin#gmail.com",
NormalizedEmail = "ADMIN#GMAIL.COM",
UserName = "Owner",
NormalizedUserName = "OWNER",
PhoneNumber = "+923366633352",
};
var password = new PasswordHasher<ApplicationUser>();
var hashed = password.HashPassword(user, "secret");
user.PasswordHash = hashed;
var userStore = new UserStore<ApplicationUser>(context);
var result = userStore.CreateAsync(user);
UserManager<ApplicationUser> _userManager = serviceProvider.GetService<UserManager<ApplicationUser>>();
//If I try this way - it keeeps on awaiting.
// var result =await _userManager.CreateAsync(user, "lol");
//the role seems to be working fine
var result2 = await _userManager.AddToRoleAsync(user, "Administrator");
}
}
}
I am having issues with getting the Authorise function to work on a controller. I have seeded a user as follows
protected override void Seed(WebApplication1.Models.ApplicationDbContext context)
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if(!context.Users.Any(t => t.UserName == "markabarmi#hotmail.com"))
{
var user = new ApplicationUser { UserName = "markabarmi#hotmail.com", Email = "markabarmi#hotmail.com" };
userManager.Create(user, "passw0d!");
context.Roles.AddOrUpdate(r => r.Name, new IdentityRole { Name = "Admin" });
context.SaveChanges();
userManager.AddToRole(user.Id, "Admin");
}
}
From this I can log into the standard MVC5 application. But when I wish to put an Authorise onto a controller or ActionResult, the login will fail and I get Invalid login attempt. This is the home controller i'm adding Authorised onto.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
//[Authorize(Roles = "Admin")]
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
If anyone could help me please :) Thanks
Not sure why you are not using a RoleManager since you have the UserManager part, but this is what works for me. AddToRole() will do it's own Saving so no need for context.SaveChanges():
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
if (!context.Roles.Any())
{
// Add missing roles
var role = roleManager.FindByName("Admin");
if (role == null)
{
role = new IdentityRole("Admin");
roleManager.Create(role);
}
role = roleManager.FindByName("DataEntry");
if (role == null)
{
role = new IdentityRole("DataEntry");
roleManager.Create(role);
}
role = roleManager.FindByName("Limited");
if (role == null)
{
role = new IdentityRole("Limited");
roleManager.Create(role);
}
}
if (!context.Users.Any())
{
var user = userManager.FindByName("admin");
if (user == null)
{
var newUser = new ApplicationUser()
{
UserName = "admin",
FirstName = "Admin",
LastName = "User",
Email = "xxx#xxx.net",
PhoneNumber = "5556667777",
MustChangePassword = false
};
userManager.Create(newUser, "Password1");
userManager.SetLockoutEnabled(newUser.Id, false);
userManager.AddToRole(newUser.Id, "Admin");
}
}
I am working on a single page application using the asp.net mvc 5 template and registering external logins (google in this instance) fails with a validation exception - "The UserId field is required."
the code in question:
// POST api/Account/RegisterExternal [OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
IdentityUser user = new IdentityUser//(model.UserName);
{
UserName = model.UserName
};
user.Logins.Add(new IdentityUserLogin
{
LoginProvider = externalLogin.LoginProvider,
ProviderKey = externalLogin.ProviderKey
});
IdentityResult result = await UserManager.CreateAsync(user);
IHttpActionResult errorResult = GetErrorResult(result);
if (errorResult != null)
{
return errorResult;
}
return Ok();
}
catch (Exception exception)
{
throw;
}
}
I appreciate the help
The fix was simple but I find it strange it that the code generated by the template doesn't work out of the box. The IdentityUserLogin object has a UserID property that must be set.
IdentityUser user = new IdentityUser
{
UserName = model.UserName
};
user.Logins.Add(new IdentityUserLogin()
{
LoginProvider = externalLogin.LoginProvider,
ProviderKey = externalLogin.ProviderKey,
UserId = user.Id
});
IdentityResult result = await UserManager.CreateAsync(user);