Customizando layout de login no ASP.NET Identity

O ASP.NET Identity é perfeito para gerenciamento de usuários e pode ser customizado facilmente. O MVP Eduardo Pires tem bastante material sobre o Identity que estão me ajudando bastante com os estudos em ASP.NET. Por sinal, tive a oportunidade de fazer o curso online de ASP.NET MVC 5 com ele e recomendo a todos. Ótima didática e conteúdo muito bom.

De fato, é muito simples implementar o gerenciamento de usuários. Por padrão o Identity será configurado se você não remover o recurso de autenticação durante a criação do projeto.

O meu intuito com esse post, é criar um projeto de autenticação customizando o comportamento da aplicação pensando numa aplicação corporativa. Para isso, irei fazer algumas customizações no template de login e também na área restrita contendo painel de admin, registro de usuários e alguns CRUD's básicos.

Nesse primeiro projeto, irei utilizar apenas o Bootstrap para customização das telas de apresentação e o projeto MVC não será desacoplado, conforme sugere o DDD. A idéia é evoluir com o projeto.

Vamos lá, mão na massa...

1 - Crie um projeto ASP.NET Web Application, MVC e autenticação "Individual User Account"

2 - Após a criação do projeto, ele funcionará com o template padrão e terá rotinas de registro e login de usuário funcionais.

Capturar1

O objetivo é alterar o comportamento obrigando o usuário a efetuar login ao acessar a aplicação. Para isso, aplique o atributo AuthorizeAttribute na HomeController.cs;

[Authorize]
public class HomeController : Controller
{ ... }

3 - O próximo passo é customizar o layout da página de login. Para isso crie uma Partial View na pasta \View\Shared do projeto chamada _LoginStart.cshtml e crie o conteúdo conforme o código abaixo;
_LoginStart.cshtml

 
 <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body class="login-page">
    <div class="container body-content">
        @RenderBody()
    </div>
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

4 - Em seguida, vamos substituir o layout padrão que é carregado através da _ViewStart somente na view de Login e customizar adicionando algumas tags e decorando com algumas classes CSS/Bootstrap.
Login.cshtml

@{
    Layout = "~/Views/Shared/_LoginStart.cshtml";
}
 
@using IdentityLoginCustomizado.Models
@model LoginViewModel
<div class="modal show" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h2 class="text-center">Bem vindo!</h2>
                <h4 class="text-center">Por favor, digite o seu usuário e senha.</h4>
            </div>
            <div class="modal-body">
                <section id="loginForm">
                    @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form col-md-12 center-block", role = "form" }))
                    {
                        @Html.AntiForgeryToken()
                        @Html.ValidationSummary(true, "", new { @class = "alert alert-danger" })
                        <div class="form-group">
                            @Html.TextBoxFor(m => m.Email, new { @class = "form-control input-lg", @placeholder = "Username" })
                            @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
                        </div>
                        <div class="form-group">
                            @Html.PasswordFor(m => m.Password, new { @class = "form-control  input-lg", @placeholder = "Senha" })
                            @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                        </div>
                        <div class="form-group">
                            <div>
                                <div class="checkbox">
                                    @Html.CheckBoxFor(m => m.RememberMe)
                                    @Html.LabelFor(m => m.RememberMe)
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <div>
                                <input type="submit" value="Log in" class="btn btn-primary btn-lg btn-block" />
                            </div>
                        </div>
                        <p>
                            <span><p class="pull-right">@Html.ActionLink("Registrar uma nova conta!", "Register")</p></span>
                            <span><p>@Html.ActionLink("Esqueceu sua senha?", "ForgotPassword")</p></span>
                        </p>
                    }
                </section>
            </div>
        </div>
    </div>
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

5 - Vamos agora customizar o painel de Administração utilizando como base o template Dashboard que está disponível na página oficial do Bootstrap - Examples Bootstrap

Crie uma nova Partial View na pasta \View\Shared chamada _LayoutAdmin.cshtml. Esta partial será o layout padrão
_LayoutAdmin.cshtml

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
 
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                @Html.Partial("_LoginPartial")
            </div>
        </div>
    </nav>
    <div class="container-fluid body-content">
        <div class="row">
            <div class="col-sm-3 col-md-2 sidebar">
                <ul class="nav nav-sidebar">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                </ul>
            </div>
            <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                @RenderBody()
            </div>
        </div>
    </div>
 
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

6 - Crie um arquivo dashboard.css e adicione na pasta \Content\
dashboard.css

/*
 * Base structure
 */
 
/* Move down content because we have a fixed navbar that is 50px tall */
body {
  padding-top: 50px;
}
 
 
/*
 * Global add-ons
 */
 
.sub-header {
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}
 
/*
 * Top navigation
 * Hide default border to remove 1px line.
 */
.navbar-fixed-top {
  border: 0;
}
 
/*
 * Sidebar
 */
 
/* Hide for mobile, show later */
.sidebar {
  display: none;
}
@media (min-width: 768px) {
  .sidebar {
    position: fixed;
    top: 50px;
    bottom: 0;
    left: 0;
    z-index: 1000;
    display: block;
    padding: 20px;
    overflow-x: hidden;
    overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
    background-color: #428bca;
    border-right: 1px solid #eee;
  }
}
 
/* Sidebar navigation */
.nav-sidebar {
  margin-right: -21px; /* 20px padding + 1px border */
  margin-bottom: 20px;
  margin-left: -20px;
}
 
.nav-sidebar li a:hover,
    .nav-sidebar li a:focus {
        outline: none;
        background-color: #3671a4 !important;
}
 
.nav-sidebar &gt; li &gt; a {
  color: #fff;
  padding-right: 20px;
  padding-left: 20px;
}
.nav-sidebar &gt; .active &gt; a,
.nav-sidebar &gt; .active &gt; a:hover,
.nav-sidebar &gt; .active &gt; a:focus {
  color: #fff;
  background-color: #428bca;
}
 
 
/*
 * Main content
 */
 
.main {
  padding: 20px;
}
@media (min-width: 768px) {
  .main {
    padding-right: 40px;
    padding-left: 40px;
  }
}
.main .page-header {
  margin-top: 0;
}
 
 
/*
 * Placeholder dashboard ideas
 */
 
.placeholders {
  margin-bottom: 30px;
  text-align: center;
}
.placeholders h4 {
  margin-bottom: 0;
}
.placeholder {
  margin-bottom: 20px;
}
.placeholder img {
  display: inline-block;
  border-radius: 50%;
}

7 - Configurar o BundleConfig.cs, adicionando o arquivo dashboard.css

public class BundleConfig
{
    // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js"));
 
        bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                    "~/Scripts/jquery.validate*"));
 
        // Use the development version of Modernizr to develop with and learn from. Then, when you're
        // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
        bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                    "~/Scripts/modernizr-*"));
 
        bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
                  "~/Scripts/bootstrap.js",
                  "~/Scripts/respond.js"));
 
        bundles.Add(new StyleBundle("~/Content/css").Include(
                  "~/Content/bootstrap.css",
                  "~/Content/dashboard.css", //added
                  "~/Content/site.css"));
    }
}

8 - Altere o layout padrão na _ViewStart.cshtml

@{
    //Layout = "~/Views/Shared/_Layout.cshtml"; //removendo o layout padrão
    Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}

9 - Pra finalizar, vamos alterar o layout da página de registro de usuários, Register.cshtml e da página de recuperação de senha, ForgotPassword.cshtml.

Register.cshtml

@model IdentityLoginCustomizado.Models.RegisterViewModel
@{
    Layout = "~/Views/Shared/_LoginStart.cshtml";
    ViewBag.Title = "Registrar nova conta";
}
<div class="modal show" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h2 class="text-center">@ViewBag.Title</h2>
                <h4 class="text-center">Por favor, preencha os dados.</h4>
            </div>
            <div class="modal-body">
 
                @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form col-md-12 center-block", role = "form" }))
                {
                    @Html.AntiForgeryToken()
                    @Html.ValidationSummary("", new { @class = "text-danger" })
                    <div class="form-group">
                        @Html.TextBoxFor(m => m.Email, new { @class = "form-control input-lg", @placeholder = "E-mail" })
                    </div>
                    <div class="form-group">
                        @Html.PasswordFor(m => m.Password, new { @class = "form-control input-lg", @placeholder = "Senha" })
                    </div>
                    <div class="form-group">
                        @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control input-lg", @placeholder = "Confirmação da senha" })
                    </div>
                    <div class="form-group">
                        <div>
                            <input type="submit" class="btn btn-primary btn-lg btn-block" value="Registrar" />
                        </div>
                    </div>
                    <span><p>@Html.ActionLink("Agora não, obrigado!", "Login")</p></span>
                }
            </div>
        </div>
    </div>
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

ForgotPassword.cshtml

@model IdentityLoginCustomizado.Models.ForgotPasswordViewModel
@{
    Layout = "~/Views/Shared/_LoginStart.cshtml";
    ViewBag.Title = "Esqueceu sua senha?";
}
<div class="modal show" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h2 class="text-center">@ViewBag.Title</h2>
                <h4 class="text-center">Por favor, forneça o seu e-mail.</h4>
            </div>
            <div class="modal-body">
                @using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form col-md-12 center-block", role = "form" }))
                {
                    @Html.AntiForgeryToken()
                    @Html.ValidationSummary("", new { @class = "text-danger" })
                    <div class="form-group">
                        @Html.TextBoxFor(m => m.Email, new { @class = "form-control input-lg", @placeholder = "E-mail" })
                    </div>
                    <div class="form-group">
                        <div>
                            <input type="submit" class="btn btn-primary btn-lg btn-block" value="Enviar" />
                        </div>
                    </div>
                    <span><p>@Html.ActionLink("Retornar ao Login", "Login")</p></span>
                }
            </div>
        </div>
    </div>
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Finalizamos a aplicação. Após executá-la, registrar-se e efetuar login, note que o layout estará com aspecto de uma aplicação corporativa, com painel de navegação e exigindo sempre a autenticação.

Tela inicial:
login

Painel após login:
painel

No próximo post irei criar algumas melhorias, talvez com um painel de Admin mais profissional, tem alguns bem legais disponíveis na web, e também com a implementação de recuperação de senha por e-mail e cadastro gerenciado de usuários. Afinal, ninguém quer usuários se registrando aleatoriamente numa aplicação segura.

O código desse projeto está disponível aqui - Download projeto

Update!!! - Código do projeto no Github - Identity Login Customizado Github
É isso aí, até a próxima!

224 thoughts on “Customizando layout de login no ASP.NET Identity

  1. Hello

    YOU NEED HELP TO BUILD SEO LINKS FOR: alexandreomiranda.com ?

    WE OFFER YOU THE BEST SEO STRATEGY FOR 2021

    Increase Traffic to your websites which will lead to a higher number of customers and much more sales for you.

    If You Are Interested, I'm waiting for your response here=> seosubmitter@mail.com

    Thanks, Twyla Gayman

  2. Hello

    YOU NEED QUALITY VISITORS FOR YOUR: alexandreomiranda.com ?

    We Provide Website Traffic 100% safe for your site, from Search Engines or Social Media Sites from any country you want.
    With this traffic, you can boost ranking in SERP, SEO, profit from CPM

    CLAIM YOUR 24 HOURS FREE TEST HERE=> ventfara@mail.com

    Thanks, Veronica Windham

  3. After looking into a few of the blog posts on your web page, I really like your way of blogging. I saved as a favorite it to my bookmark webpage list and will be checking back soon. Please visit my website too and let me know how you feel. https://www.omgka.com

  4. I like what you guys are usually up too. This kind of clever work and coverage! Keep up the very good works guys I’ve incorporated you guys to blogroll.

  5. Guy .. Excellent .. Amazing
    .. I will bookmark your website and take the feeds also?I
    am glad to search out a lot of useful info here in the put up,
    we’d like work out more techniques on this regard, thank you
    for sharing. https://www.omgab.com

  6. was announced, the President-elect and chief of staff Ron Klain were said to be looking for someone who appeared above political reproach when making decisions about Trump-era investigations in the Department of Justice under the Biden administration.
    카지노사이트

  7. While many Cabinet picks have been longtime advisers and loyalists to Biden, people familiar with the matter say the choice of attorney general is being viewed in a different light, in part because of the newly announced federal probe into Hunter Biden's business dealings in China, which was launched before the election but did not become public until earlier this month.
    카지노사이트

  8. Because many of the people being considered for attorney general are White, sources said there is a desire inside Biden's orbit to roll out selections for other top Justice Department jobs, including possibly deputy attorney general and the head of the department's civil rights division.
    카지노사이트

  9. None of Biden's earlier Cabinet picks were made in a vacuum and all have been subject to both internal and external pressures. But the choice of attorney general has been more fraught, underscoring the tug of war that has come alive inside the Democratic Party, with civil rights groups and progressives working hard to influence Biden's decision.
    카지노사이트

Leave a Reply

Your email address will not be published. Required fields are marked *

This blog is kept spam free by WP-SpamFree.