Buscar

Autenticação e Autorização em Asp.Net MVC 5

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 26 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 26 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 26 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Versão 0.0.1 – 01/06/2020 
Guia de Desenvolvimento Asp.Net MVC 5 – 
Projeto SistemaFila – Parte 2 
Autorização e Autenticação
 
2 
 
Introdução 
Neste documento veremos como implementar a autenticação e a autorização em uma aplicação Asp.Net MVC 5 para 
o acesso através de navegadores web. A autenticação e autorização para serviços RESTFull será feita de 
posteriormente para permitir acesso aos dados de nossa aplicação por clientes mobile Android e utilizará um 
mecanismo diferente. 
Este documento é uma continuação. Na parte 1 configuramos o acesso ao banco de dados e implementamos um CRUD 
utilizando o assistente presente no Visual Studio. Para conferir acesse o documento 
“GuiaDeDesenvolvimentoAspNetMVC5–SistemaFila–Parte1.pdf”. 
A ideia da aplicação de exemplo é um sistema que gerencie as filas, tanto presencial quanto virtual, para diferentes 
comércios de forma que esses comércios possam evitar aglomerações e assim conviver melhor com a atual pandemia. 
Para saber como criar um novo projeto Asp.Net MVC 5 consulte o documento “Como criar um projeto ASP NET MVC 
5.pdf”. 
Autenticação e Autorização 
Apesar de estarem muito relacionados, autenticação e autorização são coisas diferentes. Autenticação de um usuário 
diz respeito ao procedimento de confirmar/estabelecer a identidade de quem acessa o sistema, isto é, garantir que o 
usuário é quem ele afirma ser mediante o fornecimento de uma identidade juntamente com uma ou mais credenciais 
como senhas e certificados digitais. Já a autorização é o procedimento de garantir que apenas os usuários com direito 
de utilizar um recurso possam fazê-lo. A autorização pode ser baseada no perfil do usuário, no horário de acesso, no 
tipo de dispositivo utilizado ou no local de onde o usuário tenta acessar o recurso, entre outros. 
O protocolo HTTP e os Cookies 
O protocolo HTTP, que nos permite acessar páginas web, não possui estado (em inglês, stateless) pois, à princípio, o 
servidor web não consegue dizer se quem fez uma requisição http agora foi o mesmo que fez a requisição http anterior. 
Apesar do protocolo não dispor de um mecanismo nativo para “amarrar” um conjunto de requisições como sendo de 
um mesmo usuário foi desenvolvida, através do uso de cookies, uma forma de superar essa limitação. Um cookie é 
um pequeno pedaço de informação, no formato chave-valor, que o servidor envia para o cliente e que fica armazenado 
no cliente durante um certo período. O cliente, então, ao fazer outras requisições, passará essa informação para o 
servidor que, ao lembrar dela, saberá que a requisição atual pertence ao mesmo usuário daquela outra. 
 
A partir de um cookie de sessão, um dado produzido por uma requisição pode ser armazenado no servidor de forma 
que possa ser recuperado em uma requisição futura da mesma sessão. Um caso típico de uso de informações 
guardadas na sessão no servidor seriam os itens de um carrinho de compras. Para guardarmos informações na sessão 
dentro de um Controller basta fazermos o seguinte: 
 Session["lista_ids"] = "10,20,30"; 
 Session["Total"] = "153.34"; 
 
3 
 
Além de podermos armazenarmos informações no servidor, na sessão do usuário, também podemos guardar algumas 
informações diretamente dentro dos cookies. Essa estratégia é bastante utilizada para informações que o usuário 
digita frequentemente. Veja um exemplo de criação, recuperação, alteração e envio de um cookie para o 
browser(navegador) em Asp.Net MVC: 
 public ActionResult Index() 
 { 
 //Recupera o valor do cookie de nome "passei_por_aqui" 
 HttpCookie cookie = Request.Cookies.Get("passei_por_aqui"); 
 if (cookie == null) 
 { 
 //Instancia o cookie com nome "passei_por_aqui" 
 cookie = new HttpCookie("passei_por_aqui"); 
 //Estabelece a expiração do cookie para daqui 1 dia 
 cookie.Expires = DateTimeOffset.Now.AddDays(1).DateTime; 
 //Define o valor armazenado no cookie 
 cookie.Value = "0"; 
 } 
 //Converte e adiciona 1 no valor do cookie 
 cookie.Value = "" + (Int32.Parse(cookie.Value) + 1); 
 //Adiciona o cookie na resposta 
 Response.Cookies.Add(cookie); 
 //Salva o cookie na ViewBag para usar na View 
 ViewBag.ValorCookie = cookie.Value; 
 return View(); 
 } 
Em nossa aplicação, em vez de armazenarmos informações sobre o perfil do usuário na sessão do usuário no servidor, 
armazenaremos essas informações em um cookie no cliente. Para que essa informação não possa ser adulterada, o 
que poderia permitir que nossa aplicação fosse hackeada, as informações da sessão do usuário dentro do cookie serão 
criptografadas de forma que apenas o servidor possa descriptografá-las a cada requisição do usuário. Abaixo vemos 
os cookies de sessão e de autenticação criados por nossa aplicação: 
 
Owin e Asp.Net Identity 
O Asp.Net Identity é um pacote construído sobre a especificação Owin (Open Web Interface for .NET) que define uma 
interface padrão entre servidores web .NET e as aplicações web. Ele tem o objetivo de desacoplar a aplicação do 
servidor. Anteriormente, aplicações Asp.Net só podiam ser executadas sobre o servidor IIS (Internet Information 
Server) da Microsoft. Com o OWIN passou a ser possível executar uma mesma aplicação Asp.Net em outros servidores 
 
4 
 
web e em outros sistemas operacionais. Além disso, com uma especificação aberta como é o OWIN, passa a ser 
possível e encorajado que terceiros implementem componentes estendendo as funcionalidades do ecossistema .NET 
permitindo, entre outras coisas, que a autenticação/autorização seja feita separadamente de nossa aplicação como 
vemos quando uma aplicação permite que um usuário faça login por meio de sua identidade em uma rede social sem 
que a aplicação precise ter acesso à dados sigilosos como o usuário e senha do usuário naquela rede social. Neste 
documento não abordaremos esse tipo de validação mas usar padrões de mercado como o Owin sempre facilita 
possível integrações futuras dos nossos sistemas ao ecossistema atual de software. 
Alterações no Model 
Classe Usuario e UsuarioRepository 
Para implementarmos a autenticação e autorização precisamos possuir dados que nos permitam identificar o usuário. 
Para isso devemos criar uma classe Usuario que representará uma tabela no nosso banco de dados com os dados dos 
usuários bem como suas credenciais, em nosso caso, uma senha. Essa senha será armazenada no banco através de 
seu hash. Isso é importante para evitar que alguém que possua acesso ao banco de dados consiga descobrir as senhas 
dos usuários. Para executar o trabalho de geração do hash incluímos um método static GerarHash() que recebe a 
senha “aberta” e retorna o hash. Esse método utiliza o algoritmo MD5. 
De acordo com a wikipédia “Uma função hash é um algoritmo que mapeia dados de comprimento variável para dados 
de comprimento fixo. Os valores retornados por uma função hash são chamados valores hash, códigos hash, somas 
hash (hash sums), checksums ou simplesmente hashes”. A função hash, no nosso caso, servirá para cifrar/esconder o 
conteúdo da senha. É parecido quando falamos na língua do pê para impedir que outras pessoas saibam sobre o que 
estamos falando. No momento de o usuário fazer o login em nossa aplicação ele fornecerá senha “aberta”, sem 
nenhuma cifragem. Nossa aplicação aplicará o algoritmo de hash sobre a senha aberta e produzirá o código hash da 
senha. Esse código é então comparado com o código hash armazenado. Se eles forem iguais, então, a aplicação 
considerará que a senha está correta e permitirá o acesso. Como 2 senhas diferentes só produzem o mesmo código 
hash em raríssimos casos, podemos usar essa estratégia sem a preocupação de, acidentalmente, um invasor acessar 
a conta de um usuário com uma senha diferente daquelaque o usuário informou quando se cadastrou no sistema. 
 
Para fornecer acesso aos dados dos usuários criaremos uma classe que fará o papel de repositório concentrando a 
inteligência de consulta à base de dados. O repositório, aqui, corresponde ao que chamamos de design pattern 
(padrão de projeto). Em linhas gerais, um padrão de projeto consiste em um modelo de solução para um problema 
recorrente. No caso do padrão repositório ele resolve o problema de termos espalhado por vários pontos do nosso 
programa o código referente ao acesso aos dados. Ter esse código espalhado dificulta, por exemplo, que percebamos 
quando uma consulta já foi criada em outro ponto ou que duas consultas podem ser combinadas. 
Adicionando a classe Usuario 
1 – Clique com o botão direito do mouse na pasta Models >> Adicionar >> Classe 
https://pt.wikipedia.org/wiki/Algoritmo
https://pt.wikipedia.org/wiki/Dados_(computa%C3%A7%C3%A3o)
 
5 
 
 
2 – Preencha o nome da classe e clique em Adicionar 
 
3 – Preencha a classe com o código abaixo: 
using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.ComponentModel.DataAnnotations.Schema; 
using System.Linq; 
using System.Security.Cryptography; 
using System.Text; 
using System.Web; 
 
namespace SistemaFila.Models 
{ 
 public enum TipoUsuario 
 { 
 COMUM, 
 MASTER 
 } 
 public enum StatusUsuario 
 { 
 ATIVO, 
 
6 
 
 INATIVO 
 } 
 public class Usuario 
 { 
 public int UsuarioId { get; set; } 
 
 public string Nome { get; set; } 
 
 public string Endereco { get; set; } 
 
 [Required]//Torna email obrigatório 
 [Index(IsUnique = true)]//Impede que 2 usuarios tenham o mesmo email 
 [StringLength(100)]//A anotacao Index não deve ser usado com um campo nvarchar(MAX) 
 public string Email { get; set; } 
 
 //Guarda o Hash da Senha 
 public string HashSenha { get; set; } 
 
 public TipoUsuario Tipo { get; set; } = TipoUsuario.COMUM; 
 
 public StatusUsuario Status { get; set; } = StatusUsuario.ATIVO; 
 
 public static string GerarHash(string senha) 
 { 
 using (MD5 md5Hash = MD5.Create()) 
 { 
 //Converte a senha para um array de bytes e calcula o hash 
 byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(senha)); 
 
 //Cria um StringBuilder para coletar os bytes e criar a string com o hash 
 StringBuilder sBuilder = new StringBuilder(); 
 
 //Esse laço percorre cada byte do array de bytes do hash 
 //e obtendo sua representação hexadecimal 
 for (int i = 0; i < data.Length; i++) 
 { 
 //cada byte se transforam em 2 caracteres hexa(0..9,A..F) 
 sBuilder.Append(data[i].ToString("x2")); 
 } 
 
 //retorna a string hexadecimal correspondente ao hash 
 return sBuilder.ToString(); 
 } 
 } 
 } 
} 
Observe que a classe Usuario possui 2 atributos que são enum’s: o atributo Tipo que é do tipo TipoUsuario e o atributo 
Status que é do tipo StatusUsuario. Ambos são enum’s definidos no mesmo arquivo da classe Usuario. É bom lembrar 
que quando definimos uma enum restringimos os valores possíveis que uma variável daquele tipo poderá possuir. No 
caso do campo Tipo são permitidos apenas os valores COMUM e MASTER que representam o perfil do usuário e serão 
utilizado para dizer quando um usuário pode ou não acessar as funcionalidades administrativas do site como um todo. 
Entre essas funções administrativas pode estar a capacidade de inativar um usuário qualquer por não cumprir com as 
regras de conduta do site. Isso se relaciona com o outro atributo do tipo enum. O atributo Status permite que 
implementemos o que é chamado de exclusão lógica, que contrasta com a exclusão física no banco de dados. Na 
exclusão física um registro do banco de dados é eliminado de forma irreversível. Essa operação no banco de dados é 
efetuada pela execução de um comando DELETE. Eliminar os dados de um usuário de forma permanente tem uma 
série de implicações como impedir o rastreamento de suas ações enquanto utilizou a aplicação ou dificultar que 
usuários antigos voltem a utilizar a aplicação obrigando-os a informar todos os seus dados novamente. Com a exclusão 
lógica mantemos todos os dados dos usuários para qualquer necessidade futura e podemos reativar um usuário antigo 
com apenas um comando sql. Para isso basta que todas as consultas que deveriam retornar os usuários só retornem 
aqueles registros que possuem o campo Status com o valor ATIVO. Ao alterar, em um determinado registro, o valor 
 
7 
 
do campo Status para INATIVO, fazemos com que esse registro fique “invisível” a estas consultas como se ele tivesse 
sido excluído. Isso só funciona se em todos os pontos do código que a aplicação busca um usuário for levado em 
consideração o campo Status e esse é um dos motivos para criarmos a figura do UsuarioRepository que centraliza 
todas as consultas relacionadas à Usuario. 
4 – Em SistemaFilaContext.cs, dentro de DAL, adicione o atributo Usuarios, veja abaixo: 
using SistemaFila.Models; 
using System; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.Data.Entity.ModelConfiguration.Conventions; 
using System.Linq; 
using System.Web; 
 
namespace SistemaFila.DAL 
{ 
 public class SistemaFilaContext : DbContext 
 { 
 public SistemaFilaContext() : base("SistemaFilaContext") 
 { 
 
 } 
 public DbSet<Comercio> Comercios { get; set; } 
 public DbSet<Fila> Filas { get; set; } 
 public DbSet<Usuario> Usuarios { get; set; } 
 protected override void OnModelCreating(DbModelBuilder modelBuilder) 
 { 
 //Por padrao as tabelas ficariam no plural, aqui removemos esse 
 //padrão e as tabelas ficarao com o mesmo nome das classes 
 modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 
 } 
 } 
} 
Adicionando a classe UsuarioRepository 
1 – Crie um diretório Repositories no projeto. Botão direito do mouse na raiz do projeto >> Adicionar >> Nova Pasta 
 
 
 
8 
 
2 – Criar uma classe UsuarioRepository.cs dentro de Repositories. Botão direito do mouse na pasta Repositories >> 
Adicionar >> “Classe...”. Na sequência preencha o campo “Nome” com “UsuarioRepository.cs” e clique em Adicionar. 
 
 
 
3 – Preencha a classe UsuarioRepository.cs com o código abaixo: 
 
9 
 
using SistemaFila.DAL; 
using SistemaFila.Models; 
using System; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.Linq; 
using System.Web; 
 
namespace SistemaFila.Repositories 
{ 
 public class UsuarioRepository : IDisposable 
 { 
 private readonly SistemaFilaContext db; 
 private bool disposed = false; 
 
 public UsuarioRepository(SistemaFilaContext context) 
 { 
 this.db = context; 
 } 
 public IEnumerable<Usuario> BuscarTodos() 
 { 
 return db.Usuarios 
 .Where(u => u.Status == StatusUsuario.ATIVO) 
 .ToList(); 
 } 
 public Usuario BuscarPorId(int UsuarioId) 
 { 
 return db.Usuarios.Find(UsuarioId); 
 } 
 
 public Usuario BuscarPorEmail(string email) 
 { 
 return db.Usuarios 
 .Where(u => u.Email == email) 
 .Where(u => u.Status == StatusUsuario.ATIVO) 
 .FirstOrDefault(); 
 } 
 public void Criar(Usuario usuario) 
 { 
 if (usuario != null) 
 { 
 db.Usuarios.Add(usuario); 
 db.SaveChanges(); 
 } 
 } 
 public void Salvar(Usuario usuario) 
 { 
 if (usuario != null){ 
 db.Entry(usuario).State = EntityState.Modified; 
 db.SaveChanges(); 
 } 
 } 
 public void Apagar(int UsuarioId) 
 { 
 Usuario usuario = db.Usuarios.Find(UsuarioId); 
 if (usuario != null) 
 { 
 usuario.Status = StatusUsuario.INATIVO; 
 } 
 Salvar(usuario); 
 } 
 //Bloco para liberar os recursos alocados - INICIO 
 protected virtual void Dispose(bool disposing) 
 { 
 if (!this.disposed) 
 
10 
 
 { 
 if (disposing) 
 { 
 db.Dispose(); 
 } 
 } 
 this.disposed = true; 
 } 
 public void Dispose() 
 { 
 Dispose(true); 
 GC.SuppressFinalize(this); 
 } 
 //Bloco para liberar os recursos alocados - FIM 
 } 
} 
Carga inicial de dados de usuário 
Na classe SistemaFilaInitializer.cs, dentro do método Seed, adicione o seguinte trecho no final do método 
 ... 
 var comum = new Usuario 
 { 
 Nome = "Zé Zinho", 
 Email = "ze@gmail.com", 
 Endereco = "Rua Bandeirantes, 100", 
 HashSenha = "81dc9bdb52d04dc20036dbd8313ed055",//hash md5 para 1234 
 Tipo = TipoUsuario.COMUM, 
 Status = StatusUsuario.ATIVO 
 }; 
 
 var master = new Usuario 
 { 
 Nome = "Jão da Silva", 
 Email = "jao@gmail.com", 
 Endereco = "Avenida dos Autonomistas, 1000", 
 HashSenha = "81dc9bdb52d04dc20036dbd8313ed055",//hash md5 para 1234 
 Tipo = TipoUsuario.MASTER, 
 Status = StatusUsuario.ATIVO 
 }; 
 
 var inativo = new Usuario 
 { 
 Nome = "José Carlos", 
 Email = "zeca@gmail.com", 
 Endereco = "Rua Carlos Magno, sem número", 
 HashSenha = "81dc9bdb52d04dc20036dbd8313ed055",//hash md5 para 1234 
 Tipo = TipoUsuario.COMUM, 
 Status = StatusUsuario.INATIVO 
 }; 
 context.Usuarios.Add(comum); 
 context.Usuarios.Add(master); 
 context.Usuarios.Add(inativo); 
 
 context.SaveChanges(); 
 ... 
Ao executarmos a aplicação a tabela Usuario será criada com o seguinte conteúdo 
 
 
11 
 
Observe que os campos correspondentes aos tipos enum(Tipo e Status) são mapeadas em valores inteiros, o primeiro 
item é mapeado no 0, o segundo no 1 e assim sucessivamente. 
Owin/Asp.Net Identity 
Instalando os pacotes OWIN/Asp.Net Identity 
Deverão ser instalados os seguintes pacotes: 
Microsoft.Owin.Host.SystemWeb — ASP.NET identity é, na verdade, construída em cima do Owin o que significa que 
as mesmas características do identity podem ser usadas para qualquer framework que suporta Owin tais como API 
Web e SignalR. Este pacote permite ao Owin middleware acionar o pipeline de solicitação do IIS. 
Microsoft.Owin.Security.Cookies — Este é o pacote que realmente permite a autenticação baseada em cookie. 
1 – Clique com o botão direito do mouse na raiz do projeto >> “Gerenciar Pacotes do NuGet...” 
 
2 – Na aba “Procurar”, pesquise pelo pacote “Microsoft.Owin.Host.SystemWeb” e clique em Instalar. 
 
 
12 
 
3 – Clique em OK 4 – Clique em Aceitar 
 
5 – Na aba “Procurar”, pesquise pelo pacote “Microsoft.Owin.Security.Cookies” e clique em Instalar. 
 
 
13 
 
6 – Clique em OK 7 – Clique em Aceitar 
 
 
Adicionando a classe de inicialização do Owin/Asp.Net Identity 
1 – Clique com o botão direito do mouse na raiz do projeto >> Adicionar >> Novo Item... 
 
 
14 
 
2 – Escolha a opção “Classe de inicialização OWIN”, preencha “OwinStartup.cs” no campo “Nome” e clique em 
“Adicionar”. 
 
3 – Preencha a classe OwinStartup.cs com o código abaixo: 
using System; 
using System.Threading.Tasks; 
using Microsoft.Owin; 
using Microsoft.Owin.Security.Cookies; 
using Owin; 
 
[assembly: OwinStartup(typeof(SistemaFila.OwinStartup))] 
 
namespace SistemaFila 
{ 
 public class OwinStartup 
 { 
 public void Configuration(IAppBuilder app) 
 { 
 app.UseCookieAuthentication(new CookieAuthenticationOptions() 
 { 
 AuthenticationType = "ApplicationCookie", 
 LoginPath = new PathString("/Home/Login"), 
 ExpireTimeSpan = TimeSpan.FromMinutes(10) 
 
 }); 
 } 
 } 
} 
 
A extensão UseCookieAuthentication diz ao framework ASP.NET identity para usar a autenticação baseada em cookie. 
Precisamos definir 3 propriedades: 
 
15 
 
AuthenticationType — Este parâmetro é uma string que identifica o cookie. Isto é necessário, uma vez que podem 
existir várias instâncias do middleware Cookie. Por exemplo, quando se utiliza servidores de autenticação externos 
(OAuth / OpenID) o mesmo middleware cookie é usado para passar reivindicações do provedor externo. 
LoginPath — O caminho para o qual o cliente do usuário (navegador) deve ser redirecionado quando seu aplicativo 
retorna uma resposta não autorizada (401). Este deve corresponder ao seu controlador “login”. Neste caso, eu tenho 
uma HomeContoller com uma ação de Login. 
ExpireTimeSpan — Controla quanto tempo um cookie permanece válido após sua criação. 
Restringindo o acesso 
Filtros 
No Asp.Net MVC, uma requisição do usuário é encaminhada para a Action apropriada em um Controller. Entretanto, 
em certas circunstâncias, nós desejamos executar alguma lógica antes ou depois da execução da Action. Para este fim 
existem os Filtros. 
O Asp.Net Mvc possui diferentes tipos de filtros. Abaixo segue uma tabela com os tipos de filtros, exemplos de filtros 
prontos e as interfaces que eles implementam: 
Tipo de Filtro Descrição 
Exemplo de 
filtro pronto 
Interface 
Authorization 
filters 
Executa a autenticação e autorização antes da execução da 
Action 
[Authorize], 
[RequireHttps] 
IAuthorizationFilter 
Action filters Executa alguma ação antes e depois da execução da Action IActionFilter 
Result filters Executa alguma ação antes e depois da execução da Action [OutputCache] IResultFilter 
Exception 
filters 
Executa alguma ação se alguma exception ocorrer e não 
for tratada em qualquer ponto do pipeline de Asp.Net 
MVC. 
[HandleError] IResultFilter 
 
Caminho de uma requisição http ao ser processada pelo pipeline Asp.Net MVC da chegado ao servidor à resposta 
ao cliente 
Confirando um filtro global 
Agora vamos restringir o acesso à todas as url’s deixando que apenas os usuários autenticados/autorizados consigam 
acessar os recursos. Por padrão, apenas os usuários do tipo COMUM ou MASTER terão permissão para chamar os 
controllers. Quando for necessário acesso anônimo, como no caso da tela de login, deveremos sobrescrever essa 
configuração diretamente na action. 
Em App_Start/FilterConfig.cs adicione o filtro Authorize como abaixo: 
using SistemaFila.Models; 
using System.Web; 
using System.Web.Mvc; 
 
namespace SistemaFila 
{ 
 
16 
 
 public class FilterConfig 
 { 
 public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
 { 
 filters.Add(new HandleErrorAttribute()); 
 filters.Add(new AuthorizeAttribute() { 
 Roles = "" + TipoUsuario.COMUM + "," + TipoUsuario.MASTER 
 }); 
 } 
 } 
} 
Para permitir que apenas o usuário do tipo MASTER possa chamar uma determinada Action, devemos sobrescrever 
essa definição global decorando a Action com 
[Authorize(Roles = "MASTER")] 
Criando a tela de login 
O que é um ViewModel? 
Muitas vezes precisamos criar telas que correspondem a um conjunto de campos que estão associados a diferentes 
objetos do nosso modelo ou simplesmenteum conjunto de campos que não se encaixam em nenhum Model. Como 
nossas classes do Model estão intimamente ligadas à estrutura do banco de dados é um problema tentar ajustá-las 
para também fazer o trabalho de capturar as informações provenientes do cliente. Quando temos um formulário que 
não se encaixa em nenhum model é necessário criar uma classe apenas para este fim. Esse é um problema recorrente 
e para ele temos um padrão de solução, um design pattern, chamado View Model. Para a tela de login criaremos um 
View Model para pegar o email e a senha e transportá-los para o servidor. 
Criando LoginViewModel 
1 – Clique com o botão direito do mouse do diretório Models >> Adicionar >> Classe... 
 
2 – Preencha o campo nome com “LoginViewModel.cs” 
 
 
17 
 
3 – Preencha LoginViewModel.cs com o código abaixo: 
using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
 
namespace SistemaFila.Models 
{ 
 public class LoginViewModel 
 { 
 public string email { get; set; } 
 
 [DataType(DataType.Password)] 
 public string senha { get; set; } 
 //Cria um campo oculto na página para armazenar a url que se 
 //tentava acessar e que levou para a tela de login pois 
 //o usuário não estava autenticado 
 } 
} 
Adicionando a view Login 
1 – Clique com o botão direito do mouse em Views/Home >> Adicionar >> Exibir... 
 
2 – Preencha o campo “Nome do modo de exibição” com “Login”, no campo “Modelo” selecione a opção 
“Empty(sem modelo)” e clique em “Adicionar”. Veja abaixo: 
 
 
18 
 
 
3 – Preencha a Login.cshtml com o código abaixo: 
@model SistemaFila.Models.LoginViewModel 
@{ 
 ViewBag.Title = "Login"; 
} 
 
<h2>Login</h2> 
 
@using (Html.BeginForm("Login", "Home", FormMethod.Post)) 
{ 
<div class="form-horizontal"> 
 <hr /> 
 @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
 <div class="form-group"> 
 @Html.LabelFor(model => model.email, 
 htmlAttributes: new { @class = "control-label col-md-2" }) 
 <div class="col-md-10"> 
 @Html.EditorFor(model => model.email, 
 new { htmlAttributes = new { @class = "form-control" } }) 
 
 </div> 
 </div> 
 
 <div class="form-group"> 
 @Html.LabelFor(model => model.senha, 
 htmlAttributes: new { @class = "control-label col-md-2" }) 
 <div class="col-md-10"> 
 @Html.PasswordFor(model => model.senha, 
 new { @class = "form-control"}) 
 </div> 
 </div> 
 
 <div class="form-group"> 
 <div class="col-md-offset-2 col-md-10"> 
 <input type="submit" value="Login" class="btn btn-default" /> 
 </div> 
 </div> 
</div> 
} 
 
@section Scripts { 
 @Scripts.Render("~/bundles/jqueryval") 
} 
 
Alterando HomeController 
1 – Abra a classe HomeController.cs e adicione os seguintes itens 
 
19 
 
1.1 – Um atributo do tipo UsuarioRepository: Este atributo será utilizado dentro do Controller para acessar os dados 
da tabela Usuario. Observe que é passado a classe de contexto do banco de dados (SistemaFilaContext) para o 
repositório. 
private UsuarioRepository usuarioRepository = new UsuarioRepository(new SistemaFilaContext()); 
1.2 – Um método Login sem parâmetros: Esse método é responsável por fornecer a tela inicial de login. Observe que 
esse método está decorado com [AllowAnonymous] para permitir o acesso dos usuários que ainda não estão 
autenticados. Quando configuramos o filtro global restringimos, por padrão, o acesso a todas as Actions. Com 
[AllowAnonymous] criamos uma exceção à essa regra. Sem essa exceção para o método Login ninguém conseguirá se 
autenticar e assim entrar no sistema. Esse método é chamado quando a url /Home/Login é chamado via método GET 
do protocolo HTTP. 
 [AllowAnonymous] 
 public ActionResult Login() 
 { 
 return View(); 
 } 
1.3 – Método Login com um parâmetro LoginViewModel: Esse método será chamado quando o usuário clicar no 
botão “Login” e efetura a submissão dos dados do formulário. Como o usuário, neste ponto, ainda não está logado, 
esse método deve permitir o acesso de não-autenticados, daí o motivo para o este método Login também estar 
decorado com [AllowAnonymous]. Para evitar um conflito de rotas com a outra versão, este método Login está 
decorado com [HttpPost] indicando que responderá apenas requisições que vierem por meio do método POST. 
Na linha 
 var user = usuarioRepository.BuscarPorEmail(loginModel.email); 
é chamado o método BuscarPorEmail de UsuarioRepository para recuperar um objeto do tipo Usuario a partir do 
email. Atenção neste ponto: apenas 1 usuário pode estar associado à um determinado email. Essa restrição nos levou 
a definir a propriedade email da classe Usuario com a anotação [Index(IsUnique = true)]. O campo email da tabela 
usuário é o que chamamos em banco de dados de chave alternativa e isso, normalmente, se reflete no script SQL com 
a constraint UNIQUE associada ao campo. A forma como temos para implementar essa restrição é assim, criando um 
índice exclusivo para o campo email. No final das contas o resultado será igual, afinal, quando criamos, no banco 
dados, um campo como chave-primária ou unique, que não permite valores repetidos, o banco de dados cria um índice 
exclusivo para garantir essa restrição. 
Analisando o método BuscarPorEmail podemos ver como uma consulta com uma cláusula where pode ser traduzida 
para o EntityFramework. 
Na sequência, caso tenha sido retornado um objeto Usuario para o email pesquisado, é feita a validação da senha 
comparando o hash da senha armazenado no banco (presente em user.HashSenha) com a chamada 
Usuario.GerarHash(loginModel.senha). 
 
 if (user != null && user.HashSenha == Usuario.GerarHash(loginModel.senha)) 
 
Caso a senha esteja correta é criado um objeto do tipo ClaimsIdentity, que funciona como uma “declaração de 
identidade” que enumera/lista informações do usuário. O termo claim pode ser traduzido como 
afirmação/reinvidicação/alegação mas o fato é que esse objeto vai ter esses dados do usuário criptografados com uma 
chave do servidor da aplicação para produzir o conteúdo do cookie “ApplicationCookie”. Toda vez que o usuário fizer 
uma requisição esse cookie é passado e o mecanismo do Asp.Net Identity descriptografa essas informações para 
podermos utilizá-las. Por isso que são incluídos o tipo do usuário, se é COMUM ou MASTER, o email do usuário, para 
 
20 
 
mostrar na parte de cima da página e também o UsuarioId, pois é com ele que obteremos as informações relacionadas 
com o usuário autenticado. 
 var identity = new ClaimsIdentity(new[] 
 { 
 new Claim(ClaimTypes.Email, loginModel.email), 
 new Claim(ClaimTypes.Role, user.Tipo.ToString()), 
 new Claim(ClaimTypes.Sid, user.UsuarioId + "") 
 }, "ApplicationCookie"); 
 
 
Método BuscarPorEmail 
Na sequência recuperamos o contexto Owin e a partir dele um objeto que representa o middleware de autenticação 
disponível na requisição. Com ele, chamando o método SignIn(), indicamos para o mecanismo de autenticação para 
assumir o usuário representado por aquela identidade com autenticado. 
 
 var context = Request.GetOwinContext(); 
 var authManager = context.Authentication; 
 authManager.SignIn(identity); 
 
 
21 
 
Caso o email não tenha sido encontrado ou o hash da senha não combine com o hash armazenado na base devemos 
retornar uma mensagem para o usuário de que “E-mail ou senha inválidos”. Para isso devemos usar o objeto 
ModelState que nos permite interagir com o mecanismo de mensagens de erro. Nesse caso temos uma mensagem 
para o form e não para um campo específico, por isso, devemos incluir a chamadaabaixo no Controller 
 
 ModelState.AddModelError(string.Empty, "E-mail ou senha inválidos"); 
 
Lembre-se: para que a mensagem seja apresentada, nosso form em Login.cshtml inclui o trecho abaixo destacado 
 
 ... 
 <hr /> 
 @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
 <div class="form-group"> 
 ... 
Aqui podemos ver o método Login completo 
 [AllowAnonymous] 
 [HttpPost] 
 public ActionResult Login(LoginViewModel loginModel) 
 { 
 //Busca o usuario por meio do repositorio passando o email 
 var user = usuarioRepository.BuscarPorEmail(loginModel.email); 
 //Verifica se encontrou o usuario e se a senha cofere 
 if (user != null && user.HashSenha == GerarHash(loginModel.senha)) 
 { 
 
 var identity = new ClaimsIdentity(new[] 
 { 
 new Claim(ClaimTypes.Email, loginModel.email), 
 new Claim(ClaimTypes.Role, user.Tipo.ToString()), 
 new Claim(ClaimTypes.Sid, user.UsuarioId + "") 
 }, "ApplicationCookie"); 
 
 var context = Request.GetOwinContext(); 
 var authManager = context.Authentication; 
 
 authManager.SignIn(identity); 
 
 return RedirectToAction("Index","Home"); 
 } else 
 { 
 ModelState.AddModelError(string.Empty, "E-mail ou senha inválidos"); 
 return View(loginModel); 
 } 
 } 
1.4 – Método LogOut: Nesse método o AuthenticationManager e chamamos seu método SignOut passando o nome 
do cookie da sessão. Com isso o usuário é deslogado. Observe que também eliminamos qualquer informação ainda 
presente na sessão evitando ocupar espaço em memória desnecessariamente. 
 public ActionResult LogOut() 
 { 
 var ctx = Request.GetOwinContext(); 
 var authManager = ctx.Authentication; 
 authManager.SignOut("ApplicationCookie"); 
 //Elimina qualquer informação que tenha sido salva na sessao 
 Session.Abandon(); 
 Session.Clear(); 
 Session.RemoveAll(); 
 return RedirectToAction("Index", "Home"); 
 } 
 
22 
 
Ajustando o menu 
Precisamos agora ajustar nosso menu para apresentar as opções de acordo com o perfil do usuário. 
• Caso o usuário não esteja autenticado, será apresentado apenas as opções para a página inicial e a página de 
login; 
• Caso o usuário esteja autenticado e seja do tipo COMUM, ele poderá ver seu e-mail na parte de cima da página 
permitindo que ele confira se está mesmo logado com seu usuário e várias opções no menu exceto a opção 
“Administrador” que dará acesso a parametrizações do site; 
• Caso o usuário seja do tipo MASTER ele verá se e-mail e todas as opções do menu incluindo o item 
“Administrador”. Além disso 
Verificando se o usuário está autenticado 
Para verificar se o usuário está autenticado, primeiramente, acessamos o conteúdo do cookie dentro de 
Views/Shared/_Layout.cshtml guardando o cookie dentro de uma variável 
 @{ 
 var Usuario = (ClaimsIdentity)User.Identity; 
 } 
E na sequência fazemos a verificação de autenticação 
@if (Usuario.IsAuthenticated) 
 
 
Modificando o menu de acordo com o tipo do usuário 
Ainda em Views/Shared/_Layout.cshtml , para mostrar a opção “Administrador” apenas para os usuários cujo tipo é 
MASTER, acessaremos o perfil (Role), também presente no cookie, em uma das Claims(afirmações) que foram incluídas 
no processo de login. Veja abaixo: 
if (Usuario.Claims.Any( 
 c => c.Type == ClaimTypes.Role 
 && c.Value == TipoUsuario.MASTER.ToString())) 
{ 
 <li>@Html.ActionLink("Administrador", "Index", "Administrador")</li> 
} 
A função Any(pode ser traduzido como “existe algum”) retorna verdadeiro caso exista algum elemento da coleção 
Claims que contenha o critério estabelecido entre parênteses, isto é, cujo tipo da Claim seja “Role” e que o valor dessa 
 
23 
 
Claim seja “MASTER”. Essa consulta usa o mesmo mecanismo que vimos sendo utilizado no método BuscarPorEmail 
mas lá a condição era passada para um método Where e aqui o método é o Any. Lembre-se: no login adicionamos um 
par chave-valor “Role=<tipo usuário>” para consultarmos aqui. 
Adicionando o email do usuário ao menu 
 
1 – Para incluirmos o e-mail no menu de forma que ele fique, juntamente com a opção “Sair”, alinhado à direita, 
vamos criar um segunda lista <ul> em que usaremos a classe css do bootstrao navbar-right e adicionaremos um classe 
css de nome “email_usuario” para alterar o estilo do texto apenas para o e-mail, veja abaixo: 
 </ul> 
 <ul class="nav navbar-nav navbar-right"> 
 @if (Usuario.IsAuthenticated) 
 { 
 <li class="email_usuario"> 
 @Usuario.Claims.Where( 
 c => c.Type == ClaimTypes.Email 
 ).FirstOrDefault().Value 
 </li> 
 <li>@Html.ActionLink("Sair", "LogOut", "Home")</li> 
 } 
 </ul> 
2 – No arquivo Content/Site.css incluiremos no final a classe “email_usuario” 
.email_usuario { 
 position: relative; 
 display: block; 
 padding: 15px; 
 color: #ffffff; 
 font-weight: 900; 
} 
 
O código completo da página Views/Shared/_Layout.cshtml segue abaixo: 
@using System.Security.Claims; 
 
24 
 
@using SistemaFila.Models; 
<!DOCTYPE html> 
<html> 
<head> 
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
 <meta charset="utf-8" /> 
 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
 <title>@ViewBag.Title - Sistema Fila</title> 
 @Styles.Render("~/Content/css") 
 @Scripts.Render("~/bundles/modernizr") 
</head> 
<body> 
 <div class="navbar navbar-inverse navbar-fixed-top"> 
 <div class="container"> 
 <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("Sistema Fila", "Index", "Home", new { area = "" }, new { @class = 
"navbar-brand" }) 
 </div> 
 <div class="navbar-collapse collapse"> 
 <ul class="nav navbar-nav"> 
 @{ 
 var Usuario = (ClaimsIdentity)User.Identity; 
 } 
 @if (Usuario.IsAuthenticated) 
 { 
 <li>@Html.ActionLink("Início", "Index", "Home")</li> 
 <li>@Html.ActionLink("Buscar Comércio", "Index", "Comercio")</li> 
 <li>@Html.ActionLink("Meus Comércios", "Meus", "Comercio")</li> 
 <li>@Html.ActionLink("Dados Pessoais", "DadosPessoais", "Usuario")</li> 
 <li>@Html.ActionLink("Sobre", "About", "Home")</li> 
 <li>@Html.ActionLink("Contato", "Contact", "Home")</li> 
 
 if (Usuario.Claims.Any( 
 c => c.Type == ClaimTypes.Role 
 && c.Value == TipoUsuario.MASTER.ToString())) 
 { 
 <li>@Html.ActionLink("Administrador", "Index", "Administrador")</li> 
 } 
 
 } 
 else 
 { 
 <li>@Html.ActionLink("Início", "Login", "Home")</li> 
 } 
 </ul> 
 <ul class="nav navbar-nav navbar-right"> 
 @if(Usuario.IsAuthenticated) 
 { 
 <li class="email_usuario"> 
 @Usuario.Claims.Where( 
 c => c.Type == ClaimTypes.Email 
 ).FirstOrDefault().Value 
 </li> 
 <li>@Html.ActionLink("Sair", "LogOut", "Home")</li> 
 } 
 </ul> 
 </div> 
 </div> 
 </div> 
 <div class="container body-content"> 
 
25 
 
 @RenderBody() 
 <hr /> 
 <footer> 
 <p>&copy; @DateTime.Now.Year - Sistema Fila</p> 
 </footer> 
 </div> 
 
 @Scripts.Render("~/bundles/jquery") 
 @Scripts.Render("~/bundles/bootstrap") 
 @RenderSection("scripts", required: false) 
</body> 
</html> 
 
Tela de Login 
 
Menu para usuário do tipo COMUM 
 
 
26 
 
Menu para usuário do tipo MASTER 
 
Bibliografia 
https://pt.wikipedia.org/wiki/Protocolos_AAA 
https://pt.wikipedia.org/wiki/Autentica%C3%A7%C3%A3o 
https://pt.wikipedia.org/wiki/Autoriza%C3%A7%C3%A3o 
https://docs.microsoft.com/pt-br/aspnet/web-api/overview/advanced/http-cookies 
https://klauslaube.com.br/2012/04/05/entendendo-os-cookies-e-sessoes.html 
https://docs.microsoft.com/pt-br/dotnet/standard/datetime/choosing-between-datetime 
https://www.tutorialsteacher.com/articles/convert-string-to-int 
https://www.c-sharpcorner.com/UploadFile/8a67c0/repository-pattern-with-Asp-Net-mvc-with-entity-framework/ 
https://stackoverflow.com/questions/151051/when-should-i-use-gc-suppressfinalize 
http://owin.org/ 
https://pt.stackoverflow.com/questions/76609/owin-e-oauth-o-que-s%C3%A3o-e-como-utilizar 
https://oauth.net/ 
https://docs.microsoft.com/pt-br/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-
4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application 
https://martinfowler.com/eaaCatalog/repository.html 
https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_hash 
https://docs.microsoft.com/pt-br/sql/relational-databases/sql-server-index-design-guide?view=sql-server-ver15 
https://www.devmedia.com.br/linq-e-csharp-efetuando-consultas-com-lambda-expressions/38863 
https://www.tutorialsteacher.com/mvc/filters-in-asp.net-mvc 
https://stackoverflow.com/questions/57352318/how-filters-short-circuit-request-pipeline 
https://www.eduardopires.net.br/2013/08/asp-net-mvc-view-model-pattern-quando-e-como-utilizar/ 
https://pt.wikipedia.org/wiki/Protocolos_AAA
https://pt.wikipedia.org/wiki/Autentica%C3%A7%C3%A3o
https://pt.wikipedia.org/wiki/Autoriza%C3%A7%C3%A3o
https://docs.microsoft.com/pt-br/aspnet/web-api/overview/advanced/http-cookies
https://klauslaube.com.br/2012/04/05/entendendo-os-cookies-e-sessoes.html
https://docs.microsoft.com/pt-br/dotnet/standard/datetime/choosing-between-datetime
https://www.tutorialsteacher.com/articles/convert-string-to-int
https://www.c-sharpcorner.com/UploadFile/8a67c0/repository-pattern-with-Asp-Net-mvc-with-entity-framework/
https://stackoverflow.com/questions/151051/when-should-i-use-gc-suppressfinalize
http://owin.org/
https://pt.stackoverflow.com/questions/76609/owin-e-oauth-o-que-s%C3%A3o-e-como-utilizar
https://oauth.net/
https://docs.microsoft.com/pt-br/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
https://docs.microsoft.com/pt-br/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
https://martinfowler.com/eaaCatalog/repository.html
https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_hash
https://docs.microsoft.com/pt-br/sql/relational-databases/sql-server-index-design-guide?view=sql-server-ver15
https://www.devmedia.com.br/linq-e-csharp-efetuando-consultas-com-lambda-expressions/38863
https://www.tutorialsteacher.com/mvc/filters-in-asp.net-mvc
https://stackoverflow.com/questions/57352318/how-filters-short-circuit-request-pipeline
https://www.eduardopires.net.br/2013/08/asp-net-mvc-view-model-pattern-quando-e-como-utilizar/

Mais conteúdos dessa disciplina