Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identity 2 - Confirm Email and then allow user to set password

I am writing an app (MVC5, Identity 2.0 and Entity Framework 6) that has a Users section that only Administrators can access. The only place to add users is in this section, unless you're registering a new Organisation (which is a parent of Users).

I have everything up and running but want to make the adding of users flow better. At present, the admin creates the user with a hard coded password and an e-mail is sent to them asking them to confirm their account. They click on this and the account is confirmed and then they have to login. Obviously, hard coding passwords is not suitable for a production app!

I would really like it for the user to be added, a random password generated, the confirm account e-mail to be sent and then once the user clicks on it, their account is confirmed and then they are re-directed to a page where they can reset their own password.

So, code ninjas, is this possible? If so, any advice would be appreciated!

like image 527
Adam Parker Avatar asked Sep 15 '16 15:09

Adam Parker


People also ask

How can I reset my asp net password?

Local users who forget their password can have a security token sent to their email account, enabling them to reset their password. The user will soon get an email with a link allowing them to reset their password. Selecting the link will take them to the Reset page.


1 Answers

Yes it is. You can remove the hard-coded password put in by the admin and replace your call to create user with var result = await UserManager.CreateAsync(user); Provide no password at this point. Make sure to dispatch a mail on creation to user to confirm email. Here's an example.

In the confirmEmail action view, you can create a password set form and post to back to confirmEmail. Sample below:

The HTTP Get ConfirmEmail

    [AllowAnonymous]
    public async Task<ActionResult> ConfirmEmail(string userId, string code)
    {
        if (userId == null || code == null)
        {
            return View("Error");
        }
        var confirmed = await UserManager.IsEmailConfirmedAsync(userId);
        if(confirmed)
        {
            return await RedirectToDashboard(userId);
        }

        var result = await UserManager.ConfirmEmailAsync(userId, code);

        if (result.Succeeded)
        {
            ViewBag.userId = userId;
            ViewBag.code = code;
        }
        return View(result.Succeeded ? "ConfirmEmail" : "Error");
    }

The HTTP POST to ConfirmEmail from your set password form:

    [HttpPost]
    [ValidateAntiForgeryToken]
    [AllowAnonymous]
    public async Task<ActionResult> ConfirmEmail(SetPasswordViewModel model, string userId, string code)
    {
        if (userId == null || code == null)
        {
            return View("Error");
        }
        if (!ModelState.IsValid)
        {
            return View(model);
        }
        var result = await UserManager.AddPasswordAsync(userId, model.NewPassword);
        if (result.Succeeded)
        {
            var user = await UserManager.FindByIdAsync(userId);
            if (user != null)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            }
            return await RedirectToDashboard(userId);
        }

        ViewBag.userId = userId;
        ViewBag.code = code;

        AddErrors(result);
        return View(model);
    }

Sample form to be put into the ConfirmEmailView

    @using (Html.BeginForm("ConfirmEmail", "Account", new { userId = ViewBag.userId, code = ViewBag.code }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
                {
                    @Html.AntiForgeryToken()

                    @Html.ValidationSummary("", new { @class = "color_orange" })
                      @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control", placeholder = "New Password" })
                      @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control", placeholder = "Confirm Password" })
                      <input type="submit" value="Set password" class="btn" />


                }

Remember to add a model to your confirmEmail view @model [ProjectName].Models.SetPasswordViewModel

And create the SetPasswordViewModel:

    public class SetPasswordViewModel
{
    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "New password")]
    public string NewPassword { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm new password")]
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}
like image 102
Chinemere Okereke Avatar answered Sep 21 '22 12:09

Chinemere Okereke