Reset Password by Admin - Without Email Link Only Admin can Reset Password, I get this code from MVC Admin reset of User Password but in my project, I get an error on the line
await store.SetPasswordHashAsync(cUser, hashedNewPassword);
Code:
//
// POST: /Account/ResetPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
ApplicationDbContext context = new ApplicationDbContext();
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context);
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser> (store);
string userId = model.Id;
string newPassword = model.NewPassword;
string hashedNewPassword = UserManager.PasswordHasher.HashPassword(newPassword);
ApplicationUser cUser = await store.FindByIdAsync(userId);
await store.SetPasswordHashAsync(cUser, hashedNewPassword);
await store.UpdateAsync(cUser);
return RedirectToAction("Index");
}
enter image description here
View code of reset pass word
EDIT: after seeing the view, the thing you can do is check if the view is actually getting an ID. Check the controller for the [get] action if it gives an id, one thing I do to check that is to temporarily change:
#Html.HiddenFor()
to
#Html.TextBoxFor()
then do a refresh.
You can also check the value of id in the breakpoint window if you are on debugging mode
Related
I am using ASP.NET MVC 5. I am creating a registration page to register an "expert", which I want to be a separate role from a user. I see that in the pre-generated AspNetRoles table there is an ID, and a Name column. Every time I try and research this I get something that shows how to create a page for an admin on how to literally create roles. I just want to get that role in my database, and then be able to assign it to a user when they are created using the experts registration page. I don't want a page that can make roles, I want to be able to do this directly in visual studio.
Thanks.
Try this.
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ??
HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Register User like this.
var user = new ApplicationUser {
UserName = "John Doe",
Email = "john.doe#foo.com"
};
// params: username and password
var result = await UserManager.CreateAsync(user, "name_birthday_cheeky");
if (result.Succeeded)
{
UserManager.AddToRole(user.Id, "expert");
//code omitted for brevity
}
I am using MVC 5 and Asp Identity for a new app I am building. I need to modify the login process so only information pertaining to the users community is shown. I was thinking of creating another table with Community ID's and User ID's in it similar to the AspUserRoles table. How do I tie this into the login process? Sorry I am new to MVC coming from Web Forms :(
Thanks!
Seems like a valid approach. So you'll end up with something like:
public class Community
{
...
public virtual ICollection<ApplicationUser> Members { get; set; }
}
public class ApplicationUser : IdentityUser
{
...
public virtual ICollection<Community> Communities { get; set; }
}
Entity Framework will automatically generate a join table from that. Then, in your login, somehow, you feed the community id. That could be from a special URL, a hidden input, select box, whatever. It's up to you. Then, you just need to modify the sign in process slighly. By default in a generated project template, sign in is handled via the following line:
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
You can see the code for PasswordSignInAsync here. But I'll post it here for posterity as well:
public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password,
bool isPersistent, bool shouldLockout)
{
var user = await UserManager.FindByNameAsync(userName);
if (user == null)
{
return SignInResult.Failed;
}
return await PasswordSignInAsync(user, password, isPersistent, shouldLockout);
}
So, just add your own version of this to ApplicationSignInManager in IdentiyConfig.cs:
public virtual async Task<SignInResult> PasswordSignInAsync(int communityId, string userName, string password,
bool isPersistent, bool shouldLockout)
{
var user = await UserManager.FindByNameAsync(userName);
if (user == null || !user.Communities.Any(m => m.Id == communityId))
{
return SignInResult.Failed;
}
return await PasswordSignInAsync(user, password, isPersistent, shouldLockout);
}
Notice the extra condition. Then, you just need to modify the original call in the Login action to pass in the communityId:
var result = await SignInManager.PasswordSignInAsync(communityId, model.Email, model.Password, model.RememberMe, shouldLockout: false);
Using MVC 5.1.1/VS 2013 Professional/.Net 4.5
I keep getting error once in a while (from localhost and from production IIS 7):
System.Web.Mvc.HttpAntiForgeryException: The anti-forgery cookie token and form field token do not match.
The issue seems to be when i logout a user, sometimes when i go to authenticate again thats when i get the error.
My authentication code looks like something like this:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = _uow.UserRepository.FindLogin(model.Email, model.Password);
if (user != null)
{
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Email, user.Email));
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.UserID.ToString()));
claims.Add(new Claim(ClaimTypes.Role, user.UserLevel.ToString()));
var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, id);
}
else
{
ModelState.AddModelError("", "Invalid Email Address or Password.");
}
}
return View(model);
}
Update with LogOut Method:
[HttpGet]
[AllowAnonymous]
public ActionResult LogOut(LoginViewModel model)
{
Session.Abandon();
return SignOffUser();
}
private ActionResult SignOffUser()
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return RedirectToAction("Index", "Home");
}
LogOut Form View
#if (Request.IsAuthenticated)
{
using (Html.BeginForm(null, null, FormMethod.Post, new {id = "logoutForm", #class = "navbar-right"}))
{
#Html.AntiForgeryToken()
....
}
}
Another thing you may want to look at is that on your logout page, you don't necessary validate the forgery token.
Try changing this:
[HttpGet]
[AllowAnonymous]
public ActionResult LogOut(LoginViewModel model)
{
To this
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult LogOut(LoginViewModel model)
{
My bet is that the token is changing on the page, and since it's not validated, ASP.NET doesn't know if it is truly correct or not.
E: just noticed, it should actually be an httppost on logout
Show your logout form(view).
This happens if you are calling the logout method in your controller from your view but don't have antiforgerytoken generated inside the form.
Your form should look like
#using(Html.BeginForm("Action","Controller"))
{
#Html.antiforgerytoken()
....
}
Then the action you call via your view should look like
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult MyAction()
{
return content("hello user! Antiforgerytoken has been validated1");
}
PS: No matter what action method your form calls, if you want to have antiforgery token that needs to be validated, then the form and action method should look like what I've mentioned above.
Try setting explicitly machine key in web.config (under system.web):
<machineKey validationKey="971E32D270A381E2B5954ECB4762CE401D0DF1608CAC303D527FA3DB5D70FA77667B8CF3153CE1F17C3FAF7839733A77E44000B3D8229E6E58D0C954AC2E796B" decryptionKey="1D5375942DA2B2C949798F272D3026421DDBD231757CA12C794E68E9F8CECA71" validation="SHA1" decryption="AES" />
Here's a site that generate unique Machnie Keys http://www.developerfusion.com/tools/generatemachinekey/
link: The anti-forgery cookie token and form field token do not match in MVC 4
Based on the default Identity framework, I'd like to set a session variable when the user logs in to the application.
This works well:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if(ModelState.IsValid)
{
// Validate the password
IdentityResult result = await IdentityManager.Authentication.CheckPasswordAndSignInAsync(AuthenticationManager, model.UserName, model.Password, model.RememberMe);
if(result.Success)
{
//save display name in session view
SiteUser user = await _siteDbContext.Users.SingleOrDefaultAsync(u => u.UserName == model.UserName);
Session["displayName"] = user.DisplayName;
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Which gets displayed in the site's top bar with this line:
#Html.ActionLink(Session["displayName"].ToString(), "Manage", "Account", null)
However, when the I log in with the 'Remember Me' option checked, close the browser and start it again, the session variable doesn't get set, and the page throws a null reference exception.
Digging around a little, it appears as if the /Account/Login action is set as the default login path, but it never gets called with the cookie authentication.
How can I get in the middle - or right after - of the authentication process and set my session variable?
using VS'12 asp.net MVC4 C# InternetApplication with KendoUI and Simplemembership EF Code first.
this is what VS gives you to start out with.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "Home");
.
.
.
Here is where i would like it to RedirectToAction to my Controller ChangeUsersInfoController, and send it the id of the newly created user.
To get the ID i have tried
1.
var UserID = (from u in db.UserProfiles
where u.UserName == User.Identity.Name
select new
{
UserID = u.UserID
}).Single();
2.
var userID = System.Web.Security.Membership.GetUser().ProviderUserKey;
return RedirectToAction("Edit","ChangeUsersInfo", userID);
I have also Tried return RedirectToAction("Edit","ChangeUsersInfo"); to see if it would let me jsut send it there without a variable.
For some reason
variable returned = Null
variable returned = Null
doesnt work because 1 and 2 didnt
seems to not redirect to the new EDIT but to the LOG IN Screen
What is the reason behind my nulls and the fail Redirect?
Yes the database has users
var userID = System.Web.Security.Membership.GetUser().ProviderUserKey;
Using the WebSecurity and System.Web.Security items will only work on subsequent request because you have not sent the auth cookie back to the client yet (this is where it pulls its data from). Given that, you should not even have to send the user Id of the user in the redirect URL...they are logged in and you can just get it at the controller/action that you are going to. By grabbing the userId from the auth ticket, you now do not have to check if the user Id passed in the URL is actually the user that is currently logged in.
Example:
Login Method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (!ModelState.IsValid)
{
//send em back with the errors
Return View();
}
try
{
WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Index", "ChangeUsersInfo");
}...
}
Change User Info Controller
[Authorize]
public ActionResult Index()
{
var userId = WebSecurity.CurrentUserId;
var model = GetUserInfoService.GetUserInfo(userId);
Return View(model);
}