ASP .NET Core MVC - Incluindo o perfil Admin e o User


Hoje vamos mostrar uma forma bem simples de incluir um perfil Admin e um usuário em uma aplicação Asp.net Core MVC.

Criar aplicações ASP .NET Core MVC com autenticação e autorização pode ser feita de forma bem simples usando o Identity e aplicar restrições de perfil às Actions dos controladores pode ser feito consultando a documentação oficial neste link: Role-based authorization in ASP .NET Core

O que não esta muito bem explicado é como definir os registros iniciais de usuários e roles no banco de dados e como atribuir um novo usuário a um perfil ou role padrão.

Veremos como fazer isso neste artigo.

Para isso vamos criar um projeto padrão ASP .NET Core MVC com o nome Aspn_Role com Autenticação baseada no Identity e a seguir definir os registros iniciais de role e user.

Criando o projeto inicial no VS 2019

Abra o VS 2019 Community e crie um novo projeto via menu File-> New Project;

Selecione o template ASP .NET Core Web Application, e, Informe o nome da solução Aspn_Role;

A seguir defina a utilização do .NET Core e ASP .NET Core 3.1 e a Authentication como Individual User Acconts escolhendo o template :  Web Application (Model-Veiw-Controller) e clique em Create:

 

Com o projeto criado vamos alterar o código do controlador HomeController na pasta Controllers incluindo um novo método Action SomenteAdmin e a respectiva view SomenteAdmin.cshtml na pasta Views/Home.

1- Código do método Action SomenteAdmin

 [Authorize(Policy ="RequerPerfilAdmin")]
 public IActionResult SomenteAdmin()
 {
       return View();
 }

Neste método Action usamos o atributo Authorize e definimos a política RequerPerfilAdmin que vai permitir o acesso somente a usuários com perfil Admin.

O código da view SomenteAdmin.cshtml é visto a seguir:

<div class="text-center">
    <h3 class="display-4">Acesso permitido somente ao perfil Admin</h3>
    <hr />
    <p>Aprenda mais sobre ASP .NET Core<a href="http://www.macoratti.net">Macoratti.net</a> :).</p>
</div>

A seguir vamos incluir um novo item de menu no arquivo _Layout.cshtml na pasta Views/Shared :

<li class="nav-item">
 <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="SomenteAdmin"> Somente Admin</a>
</li>

E para concluir vamos registrar a política criada como parte do serviço de autorização no arquivo Startup e incluir o serviço role ao identity. Para isso inclua o código abaixo no método ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
     services.AddDbContext<ApplicationDbContext>(options =>
         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));            
     services.AddDefaultIdentity<IdentityUser>(options =>
                 options.SignIn.RequireConfirmedAccount = true)
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>();
     services.AddControllersWithViews();
     services.AddRazorPages();
      services.AddAuthorization(options =>
      {
          options.AddPolicy("RequerPerfilAdmin",
             policy => policy.RequireRole("Administrator"));
      });
 }

Com isso concluímos a configuração inicial e agora vamos executar a aplicação pela primeira vez e registrar um novo usuário e a seguir aplicar o migrations.

Após isso ao tentar acessar a página SomenteAdmin com este novo usuários iremos obter a mensagem de acesso negado pois ainda não temos definido um perfil Admin na aplicação nem um usuário com este perfil.

Vamos então resolver este problema...

Armazenando as credenciais para o usuário Admin

Vamos armazenar as credenciais iniciais do usuário Admin no arquivo appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=..."
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "AdminCredentials": {
    "Email": "admin@macoratti.com",
    "Password": "Admin@2020"
  }
}

Criando o perfil Role e o usuário no banco de dados

Vamos incluir o usuário e criar o perfil na primeira carga da aplicação pois esta tarefa será realizada apenas uma única vez.

Assim no método Main() da classe Program do projeto vamos alterar o código conforme abaixo:

public class Program
{
        public static async Task Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            using (var scope = host.Services.CreateScope())
            {
                await DbInitializer.Initialize(scope.ServiceProvider);
            }
            host.Run();
        }
    ....
}

Neste código  estamos chamando o método assíncrono DbInitializer.Initialize(IServiceProvider serviceProvider) assíncrono que requer uma instância do provedor de serviços como um argumento.

Este método ainda não foi criado, assim teremos que criar o arquivo DbInitializer.cs na pasta Data e a seguir definir o código abaixo:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;
namespace Aspn_Role.Data
{
    public class DbInitializer
    {
        public static async Task Initialize(IServiceProvider serviceProvider)
        {
            var context = serviceProvider
                .GetRequiredService<ApplicationDbContext>();

            context.Database.EnsureCreated();

            var roleManager = serviceProvider
                .GetRequiredService<RoleManager<IdentityRole>>();

            var roleName = "Administrator";

            IdentityResult result;

            var roleExist = await roleManager.RoleExistsAsync(roleName);

            if (!roleExist)
            {
                result = await roleManager
                    .CreateAsync(new IdentityRole(roleName));

                if (result.Succeeded)
                {
                    var userManager = serviceProvider
                        .GetRequiredService<UserManager<IdentityUser>>();

                    var config = serviceProvider
                        .GetRequiredService<IConfiguration>();

                    var admin = await userManager
                        .FindByEmailAsync(config["AdminCredentials:Email"]);
                    if (admin == null)
                    {
                        admin = new IdentityUser()
                        {
                            UserName = config["AdminCredentials:Email"],
                            Email = config["AdminCredentials:Email"],
                            EmailConfirmed = true
                        };
                        result = await userManager
                            .CreateAsync(admin, config["AdminCredentials:Password"]);

                        if (result.Succeeded)
                        {
                            result = await userManager
                                .AddToRoleAsync(admin, roleName);
                            if (!result.Succeeded)
                            {
                                // todo:processar erros
                            }
                        }
                    }
                }
            }
        }
    }
}

Neste código é quem faz o trabalho pesado de verificar e criar o role Admin e o usuário atribuindo o usuário a este role.

Observe que os dados definidos no arquivo appsettings.json serão usados para definir o email e a password do usuário e que você deverá usar para fazer o login e poder acessar a página SomenteAdmin.

Executando o projeto e fazendo o login com as credenciais de Admin teremos o resultado abaixo:>

Pegue o código do projeto aqui:  Aspn_Role.zip (sem as referências)

"Bom é ter esperança, e aguardar em silêncio a salvação do Senhor."
Lamentações 3:26


Referências:


José Carlos Macoratti