How to Customize the Login Page for MVC / Razor Page Applications
When you create a new application using the application startup template, source code of the login page will not be inside your solution, so you can not directly change it. The login page comes from the Account Module that is used a NuGet package reference.
This document explains how to customize the login page for your own application.
Create a Login PageModel
Create a new class inheriting from the LoginModel of the Account module.
public class CustomLoginModel : LoginModel
{
public CustomLoginModel(
Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider schemeProvider,
Microsoft.Extensions.Options.IOptions<Volo.Abp.Account.Web.AbpAccountOptions> accountOptions)
: base(schemeProvider, accountOptions)
{
}
}
Naming convention is important here. If your class name doesn't end with
LoginModel
, you need to manually replace theLoginModel
using the dependency injection system.
Then you can override any method you need and add new methods and properties needed by the UI.
Overriding the Login Page UI
Create folder named Account under Pages directory and create a Login.cshtml under this folder. It will automatically override the Login.cshtml
file defined in the Account Module.
A good way to customize a page is to copy its source code. Click here for the source code of the login page. At the time this document has been written, the source code was like below:
@page
@using Volo.Abp.Account.Settings
@using Volo.Abp.Settings
@model Acme.BookStore.Web.Pages.Account.CustomLoginModel
@inject Volo.Abp.Settings.ISettingProvider SettingProvider
@if (Model.EnableLocalLogin)
{
<div class="card mt-3 shadow-sm rounded">
<div class="card-body p-5">
<h4>@L["Login"]</h4>
@if (await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled))
{
<strong>
@L["AreYouANewUser"]
<a href="@Url.Page("./Register", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})" class="text-decoration-none">@L["Register"]</a>
</strong>
}
<form method="post" class="mt-4">
<input asp-for="ReturnUrl" />
<input asp-for="ReturnUrlHash" />
<div class="form-group">
<label asp-for="LoginInput.UserNameOrEmailAddress"></label>
<input asp-for="LoginInput.UserNameOrEmailAddress" class="form-control" />
<span asp-validation-for="LoginInput.UserNameOrEmailAddress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LoginInput.Password"></label>
<input asp-for="LoginInput.Password" class="form-control" />
<span asp-validation-for="LoginInput.Password" class="text-danger"></span>
</div>
<div class="form-check">
<label asp-for="LoginInput.RememberMe" class="form-check-label">
<input asp-for="LoginInput.RememberMe" class="form-check-input" />
@Html.DisplayNameFor(m => m.LoginInput.RememberMe)
</label>
</div>
<abp-button type="submit" button-type="Primary" name="Action" value="Login" class="btn-block btn-lg mt-3">@L["Login"]</abp-button>
</form>
</div>
<div class="card-footer text-center border-0">
<abp-button type="button" button-type="Link" name="Action" value="Cancel" class="px-2 py-0">@L["Cancel"]</abp-button> @* TODO: Only show if identity server is used *@
</div>
</div>
}
@if (Model.VisibleExternalProviders.Any())
{
<div class="col-md-6">
<h4>@L["UseAnotherServiceToLogIn"]</h4>
<form asp-page="./Login" asp-page-handler="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" asp-route-returnUrlHash="@Model.ReturnUrlHash" method="post">
<input asp-for="ReturnUrl" />
<input asp-for="ReturnUrlHash" />
@foreach (var provider in Model.VisibleExternalProviders)
{
<button type="submit" class="btn btn-primary" name="provider" value="@provider.AuthenticationScheme" title="@L["GivenTenantIsNotAvailable", provider.DisplayName]">@provider.DisplayName</button>
}
</form>
</div>
}
@if (!Model.EnableLocalLogin && !Model.VisibleExternalProviders.Any())
{
<div class="alert alert-warning">
<strong>@L["InvalidLoginRequest"]</strong>
@L["ThereAreNoLoginSchemesConfiguredForThisClient"]
</div>
}
Just changed the @model
to Acme.BookStore.Web.Pages.Account.CustomLoginModel
to use the customized PageModel
class. You can change it however your application needs.
The Source Code
You can find the source code of the completed example here.
Comments
maazq 146 weeks ago
I am getting this error. The type or namespace name 'AbpAccountOptions' does not exist in the namespace 'Volo.Abp.Account.Web' (are you missing an assembly reference?)
Yunus Emre Kalkan 146 weeks ago
Hi @maazq,
This article doesn't use the commercial Account module. You can use "Volo.Abp.Account.Public.Web" namespace instead.
fg ppc 22 weeks ago
Is "Volo.Abp.Account.Public" still valid? I couldn't find it on NuGet.
Can anybody recommend a similar example for abp commercial module?
Kishore Sahasranaman 123 weeks ago
Login.cshtml
Add this below @page
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
Andrei Iorga 93 weeks ago
How can this be done if using a tiered template with blazor server ?
jerinantony1@gmail.com 64 weeks ago
I'm using ABP 6 and this code isn't working for me. I had to add this line to get rid of some of the issues
@inherits Volo.Abp.Account.Web.Pages.Account.AccountPageModel But it now complaints as "'Pages_Account_Login.ExecuteAsync()': no suitable method found to override ". Any ideas ?