Search code examples
c#asp.net-coreasp.net-core-identity

ASP.NET Core Identity - Confirm email return url


I've managed to set up SignUp and LogIn for my project with ASP.NET Core Identity. Everything works fine but there is a small thing really bugging me.

Since it is a simple project I don't want to configure account confirmation by really sending email to the user so I'm using the default templates, the user is redirected to the Account.RegisterConfirmation where they can select a link to have the account confirmed which redirects the user to the /Identity/Account/ConfirmEmail which is a blank page with the title only. I don't like it. After selecting a link to confirm the account I'd like to redirect the user to the /Account/Login. But where do I set that up?

This is what I've tried so far: Add>New Scaffolded Item>Identity>Account/ConfirmEmail(file to override) and I now I have ConfirmEmail.cshtml.cs:

[AllowAnonymous]
    public class ConfirmEmailModel : PageModel
    {
        private readonly UserManager<IdentityUser> _userManager;

        public ConfirmEmailModel(UserManager<IdentityUser> userManager)
        {
            _userManager = userManager;
        }

        [TempData]
        public string StatusMessage { get; set; }

        public async Task<IActionResult> OnGetAsync(string userId, string code)
        {
            if (userId == null || code == null)
            {
                return RedirectToPage("/Index");
            }

            var user = await _userManager.FindByIdAsync(userId);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{userId}'.");
            }

            code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
            var result = await _userManager.ConfirmEmailAsync(user, code);
            StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
            return Page();
        }
    }

Changing return Page(); to return RedirectToPage("/Account/Login"); results in InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'Project.Areas.Identity.Pages.Account.ConfirmEmailModel'.

Where do I set up the return url to /Account/Login after the email is confirmed?

I also tried without Scaffolding and overriding Account/ConfirmEmail, in Register.cshtml.cs there is

 var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

and I tried changing returnUrl = returnUrl to returnUrl = "~/Account/Login" , it didn't work.

**** UPDATE ***

Since I don't need email confirmation for such a simple project I just added this

options.SignIn.RequireConfirmedAccount = false

to the Startup class so account confirmation nor email confirmation is needed.

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
                    .AddEntityFrameworkStores<ProjectContext>();


services.Configure<IdentityOptions>(options =>
{
    options.SignIn.RequireConfirmedEmail = false;
    options.SignIn.RequireConfirmedAccount = false;
});

Solution

  • I'm using the default templates, the user is redirected to the Account.RegisterConfirmation

    In default code of configuring Identity service, we would find that RequireConfirmedAccount option is set to true, like below.

    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    

    And we can find that user will be redirected to RegisterConfirmation page after user account is create in RegisterModel class page handler.

    if (_userManager.Options.SignIn.RequireConfirmedAccount)
    {
        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
    }
    else
    {
    

    it is a simple project I don't want to configure account confirmation

    If you do not need account confirmation, you could not set RequireConfirmedAccount property (defaults to false) of SignInOptions while you configure Identity service.

    services.AddDefaultIdentity<ApplicationUser>()
            .AddEntityFrameworkStores<ProjectContext>();
    

    Or as you did, set SignIn settings explicitly.

    services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
        .AddEntityFrameworkStores<ProjectContext>();
    

    Besides, we can find that you call services.AddDefaultIdentity<ApplicationUser>(...) to configure Identity service with your custom ApplicationUser class in Startup ConfigureServices method, but you inject an instance of UserManager within ConfirmEmailModel class using UserManager<IdentityUser> (should use UserManager<ApplicationUser>), which cause the exception.

    enter image description here