.NET Core Identity as UI canceling Register

For ASP.NET Web Pages, this is an add on for the answer earlier to include ASP.Net razor Web Pages. I have separated these as if someone was to need them and not to get confused with each other. Web Pages is different as it includes code behind as web forms did.

First You will edit the Pages > _LoginPartial.cshtml

Remove line <li><a asp-page="/Account/Register">Register</a></li>

Next Edit Pages > Account > Login.cshtml. Remove the following:

                <div class="form-group">
                <p>
                    <a asp-page="./ForgotPassword">Forgot your password?</a>
                </p>
                <p>
                    <a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a>
                </p>
            </div>

Also remove:

<div class="col-md-6 col-md-offset-2">
    <section>
        <h4>Use another service to log in.</h4>
        <hr />
        @{
            if ((Model.ExternalLogins?.Count ?? 0) == 0)
            {
                <div>
                    <p>
                        There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
                        for details on setting up this ASP.NET application to support logging in via external services.
                    </p>
                </div>
            }
            else
            {
                <form asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
                    <div>
                        <p>
                            @foreach (var provider in Model.ExternalLogins)
                            {
                                <button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
                            }
                        </p>
                    </div>
                </form>
            }
        }
    </section>
</div>

Now edit the code behind Login.cshtml.cs

Remove:

public IList<AuthenticationScheme> ExternalLogins { get; set; }

Also Remove:

// Clear the existing external cookie to ensure a clean login process
        await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

Edit Pages > Account > Manage > _ManageNav.cshtml

Remove:

    @if (hasExternalLogins)
{
    <li class="@ManageNavPages.ExternalLoginsNavClass(ViewContext)"><a asp-page="./ExternalLogins">External logins</a></li>
}

Next we will remove the following files from the Pages > Account directory:

  • ExternalLogin.cshtml
  • ForgotPassword.cshtml
  • ForgotPasswordConfirmation.cshtml
  • Register.cshtml
  • ResetPassword.cshtml
  • ResetPasswordConfirmation.cshtml

Remove the following files from the Pages > Account > Manage directory:

  • ExternalLogin.cshtml

This is the official docs way of doing this.

Disable user registration

Taken from the docs:

  • Scaffold Identity. Include Account.Register, Account.Login, and Account.RegisterConfirmation

    dotnet aspnet-codegenerator identity -dc RPauth.Data.ApplicationDbContext --files "Account.Register;Account.Login;Account.RegisterConfirmation"
    
  • Update Areas/Identity/Pages/Account/Register.cshtml.cs so users can't register from this endpoint:

    public class RegisterModel : PageModel
    {
      public IActionResult OnGet()
      {
        return RedirectToPage("Login");
      }
    
      public IActionResult OnPost()
      {
        return RedirectToPage("Login");
      }
    }
    
  • Update Areas/Identity/Pages/Account/Register.cshtml to be consistent with the preceding changes:

    @page
    @model RegisterModel
    @{
        ViewData["Title"] = "Go to Login";
    }
    
    <h1>@ViewData["Title"]</h1>
    
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
    
  • Comment out or remove the registration link from Areas/Identity/Pages/Account/Login.cshtml

  • Update the Areas/Identity/Pages/Account/RegisterConfirmation page.

    • Remove the code and links from the cshtml file.
    • Remove the confirmation code from the PageModel:

      [AllowAnonymous]
      public class RegisterConfirmationModel : PageModel
      {
        public IActionResult OnGet()
        {  
          return Page();
        }
      }
      

NOTE: This will also add the default identity db context to your project. If you already have a db context, make sure to remove the one added by the scaffolding.


Unfortunately the other two answers are incorrect - the question is actually referring to the new AddDefaultIdentity() extension which uses Razor pages to serve up a default UI. The answer that does address this will not remove the register functionality as requested in the question.

Background

AddDefaultIdentity works in a similar way to AddIdentity but also includes a call to AddDefaultUI which gives your app access to the new Identity razor views (currently 28 of them), these are in a new razor class library. Note that this is not the only difference between AddDefaultIdentity and AddIdentity (see later).

In order to change the default views you need to override ("scaffold") the views in your project and you can then amend them. If you do not override the views, or if you override them and then delete the cshtml files you will simply go back to the default UI versions! Even if you remove the links to e.g. register, the user can still navigate to the default register view if they guess the URL.

Option 1 - Override Views

If you want to keep some of the default views and amend or remove others, you can override views as follows (from this doc):

  1. Right-click on your project > Add > New Scaffolded Item
  2. From the left pane of the Add Scaffold dialog, select Identity > Add
  3. In the Add Identity dialog, select the options you want

You can now either simply change the look and functionality of the view you have overridden, or to "remove" it you can have it return a 404 or redirect somewhere else. If you delete this overridden view the default UI will come back!

This approach can get messy quickly if you want to override all of the views.

Option 2 - Don't Add Default UI

Another option is to go back to the old way of adding identity which does not make a call to AddDefaultUI, the downside is that you will need to add all views yourself. You can do this as follows (from this doc - although ignore the first line about overriding all views, that applies to option 1 above):

//remove this: services.AddDefaultIdentity<IdentityUser>()
//use this instead to get the Identity basics without any default UI:
services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

//this assumes you want to continue using razor views for your identity UI
//it specifies areas can be used with razor pages and then adds an 
//authorize filter with a default policy for the folder /Account/Manage and
//the page /Account/Logout.cshtml (both of which live in Areas/Identity/Pages)
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
    .AddRazorPagesOptions(options =>
    {
        options.AllowAreas = true;
        options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
        options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
    });

//configures the application cookie to redirect on challenge, etc.
services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = $"/Identity/Account/Login";
    options.LogoutPath = $"/Identity/Account/Logout";
    options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});

//configures an email sender for e.g. password resets
services.AddSingleton<IEmailSender, EmailSender>();

Note that I'm not 100% convinced this second approach is without problems either, as mentioned above there are other differences between AddDefaultIdentity and AddIdentity. For example the latter adds the RoleManager service whereas the former does not. Also, it's unclear to me if both of these approaches will be supported and maintained equally going forward.

If in doubt about what the above options are doing (and if you have a few hours to kill) you can look at the source for AddDefaultIdentity (which also calls AddIdentityCookies and AddIdentityCore) compared to the older AddIdentity.

Option 3 - Hybrid Approach

The best option currently is probably to combine the previous 2, in the following way:

  1. Set up your project to use default identity
  2. Scaffold just the views you want to include and edit them accordingly
  3. Switch to the old AddIdentity call and include the razor options as shown in option 2 (adjusting as necessary depending on which views you've included

You now have just the views you want and they are based on the default implementations meaning most of the work is done for you for these views.