O framework .NET sempre forneceu alguns frameworks de autenticação e autorização para que os desenvolvedores focassem no negócio do sistema ao invés de gastar inúmeras horas projetando a política de autenticação e autorização. Porém, a maioria destes frameworks eram pouco customizáveis, de difícil manutenção e só funcionavam no SQL Server, como o Membership provider.

Pensando na dificuldade que os usuários passavam na configuração e na integração dos antigos memberships, a Microsoft lançou o ASP.NET Identity, que é um framework extensível, customizável, com suporte ao Owin, baseado no Entity Framework Code First e funcionava em outros bancos de dados além do SQL Server.

Neste artigo iremos explicar como funciona o ASP.NET Identity, quais são os principais assemblers e funcionalidades que possui, algumas customizações e alguns conceitos de autenticação e autorização.

Owin

Para que possamos entender o Identity é fundamental conhecer o que é o Owin, já que este suporta o Identity, e toda a parte de autenticação e autorização é baseada em middlewares disponibilizados pela Microsoft e por terceiros e que podem ser baixadas via nuget. Vale ressaltar que podemos baixar middlewares para autenticação baseados em providers externos, como contas do Facebook, Google, Twitter entre outros.

Entity Framework Code First

Como o ASP.NET Identity é baseado no EF Code First, podemos integrar nossas classes de negócio com o as classes disponibilizadas pelo Identity. Podemos também mudar o nome de tabelas, tipos e comprimentos de campos, entre outros. Não é necessário usar ou estender todas as classes do Identity, pois podemos usar apenas aquelas que, de fato, precisarmos. Vale ressaltar também que o Framework Identity dá suporte para bancos não- relacionais e relacionais diferentes do SQL Server.

Alguns benefícios

Alguns benefícios que encontramos com o uso do Identity são:

  1. Testável – Como o Identity trabalha com interfaces, ele torna-se extremamente testáveis;
  2. Suporte a Claims (declarações) – Antes do identity, os providers de autenticação somente davam suporte a roles. Porém, com o surgimento do Identity a autorização baseada em claims se tornou realidade.
  3. Portabilidade – Podemos usar com ASP.NET MVC , Web Forms, Web API e SignalR.

Principais Classes e Assemblers

Para podermos entender detalhadamente sobre a estrutura do Owin, teremos que analisar alguns assemblers e eles são:

Microsoft.AspNet.Identity.EntityFramework - Pacote compatível para usar o EF Code First com o SQL Server e o Identity. Se o leitor quiser usar outro provider, como o MySQL, deverá baixar um pacote compatível;

  • Microsoft.AspNet.Identity.Core – contém classes auxiliares e de segurança;
  • Microsoft.AspNet.Identity.OWIN – Contém um conjunto de classes para a integração do Owin.

Para exemplificar as principais interfaces do Identity, vamos analisar o seguinte desenho da Figura 1.

Interfaces do Identity

Figura 1. Interfaces do Identity

  1. Application – Podemos utilizar o Identity em diversos templates, ou seja, ele não é limitado ao MVC, pois não é apenas uma tecnologia e sim um conjunto de tecnologias, como, por exemplo: EF e o Owin.
  2. Managers – Classes fornecidas pelo Identity para manipular o usuário e suas permissões no ambiente. Para este fim, ela deverá chamar antes a camada Store.
  3. Stores – Classes fornecidas pelo Identity e pertencem a um nível mais baixo que o Manager. Nela pode-se configurar o modo com que os dados serão armazenados.
  4. Data sources – É o lugar onde os dados serão armazenados, como por exemplo: MySQL, SQL Server, entre outros.

Estrutura do Identity e Owin autentication

Antes de criar o projeto e começar a codificar, vamos analisar algumas classes fundamentais para o entendimento deste artigo. São elas:

  • IdentityUser - representa uma implementação do usuário;
  • IdentityRole - representa uma role, que basicamente contém um Id e um nome.

Note que toda classe que implementar as classes citadas herdarão suas propriedades.

Para criar o projeto, abra o Visual Studio 2013, vá em File > New Project > Web > ASP.NET Web Application > Empty > MVC, conforme mostra a Figura 2.

Criação
do projeto

Figura 2. Criação do projeto

Para trabalharmos com o Identity teremos que baixar os seguintes pacotes via nuget:

  • Install-Package Microsoft.AspNet.Identity.Owin -Version 2.1.0;
  • Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.1.0;
  • Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.0;
  • Install-Package Microsoft.Owin.Security.Cookies -Version 3.0.0;
  • Microsoft.Owin.Host.SystemWeb -Version 3.0.0.

NOTA: As versões desses pacotes são necessárias, pois, se baixarmos normalmente, poderá ocorrer um erro de incompatibilidade.

Agora vamos criar uma classe chamada usuário, que conterá os campos FirstName e LastName. Ela herdará da classe IdentityUser, conforme mostra a Listagem 1.

Listagem 1. Classe usuario

  namespace Identity.MVC.Models
  {
      public class Usuario : IdentityUser
      {
          public string FirstName { get; set; }
          public string LastName { get; set; }
   
      }
  }

Note, pela Figura 3, que a classe IdentityUser herda de IdentityUser<TKey, TLogin, TRole, TClaim>, que, por sua vez, contém inúmeras propriedades, como por exemplo: PhoneNumber, Email, roles, etc.. Logo, toda a classe que herdar de IdentityUser conterá todas as suas propriedades incluindo as suas.

Classe IdentityUser

Figura 3. Classe IdentityUser

Para armazenar estes dados no banco usando o EF teremos que criar um contexto e, para este fim, vamos adicionar no projeto uma classe chamada contexto. Note que, como foi baixado o pacote Microsoft.AspNet.Identity.EntityFramework, o Entity Framework também foi baixado automaticamente. Observe também que o assembler Identity.EntityFramework fornece a classe IdentityDbContext<TUser>, onde TUser é uma classe do tipo IdentityUser, a qual iremos usar para criar o nosso banco utilizando EF code First.

A classe contexto deverá herdar da classe IdentityDbContext<TUser>, sendo que o parâmetro TUser será o usuário criado, conforme a Listagem 2.

Listagem 2. Classe Contexto

namespace Identity.MVC.Data
  {
      public class Contexto : IdentityDbContext<Usuario>
      {
  public Contexto() : base(@"Data Source=(localdb)\mssqllocaldb; Initial    Catalog=DeviMedia; Integrated Security=True;Connect      Timeout=15;Encrypt=False;TrustServerCertificate=False")
          { 
    }
   
          protected override void OnModelCreating(DbModelBuilder modelBuilder)
          {
              base.OnModelCreating(modelBuilder);
          }
   
          public static Contexto Create()
          {
              return new Contexto();
          }
      }
  }

Note que a classe IdentityDbContext contém alguns itens como o método OnModelCreating e as propriedades DbSet necessárias para as customizações e configurações das entidades. Observe que foi criado o método Create para retornar uma instância deste contexto.

Para criar o banco teremos que habilitar o Migrations e, para este fim, vamos abrir o package Manager Console e digitar o seguinte código:

Enable-Migrations

Após este passo adicione um Migration com o código a seguir:

 Add-Migration Inicial

Por fim, para criar o banco use o seguinte código:

Update-Database

Note que, como a classe Usuario herda de IdentityUser e, por sua vez, contém as classes IdentityUserLogin, IdentityUserRole, IdentityUserClaim, o banco será gerado baseado nestas classes. A tabela AspNetUser representa o usuário e a tabela AspNetRoles as roles do usuário, como vemos na Figura 4.

Estrutura das tabelas

Figura 4. Estrutura das tabelas

Note também que a tabela AspNetUsers contém as colunas FirstName e LastName, que são as propriedades criadas na classe Usuario, conforme a Figura 5.

Colunas
da tabela AspNetUsers

Figura 5. Colunas da tabela AspNetUsers

Para que possamos gerenciar os usuários precisamos usar um manager, que utiliza um Store. Para este fim vamos criar uma classe chamada UserAppManager que herdará da classe UserManager<TUser>. Note, pela Figura 6 e Listagem 3 que a classe UserManager contém um construtor que recebe um IUserStore, que implementaremos na classe UserAppManager.

Construtor da classe UserManager

Figura 6. Construtor da classe UserManager

Listagem 3. Classe UserAppManager

namespace Identity.MVC.Models
  {
      public class UserAppManager : UserManager<Usuario>
      {
          public UserAppManager(IUserStore<Usuario> store) : base (store)
          { 
          }
      }
  }

Se formos mais afundo, veremos que a interface IUserStore é responsável por criar, deletar, modificar e selecionar os usuários, conforme a Figura 7.

Interface
IUserStore

Figura 7. Interface IUserStore

Se associarmos o nosso contexto ao IUserStore, então, através do UserAppManager, gerenciaremos o usuário.

Para associar o contexto ao UserStore, criaremos um Middlewere, o qual, para cada requisição, irá disponibilizar o contexto do EF ao UserStore.

NOTA: Como estamos usando o ASP.NET MVC, para que o Owin funcione no IIS teremos que baixar o pacote Microsoft.Owin.Host.SystemWeb.

Por fim, criaremos a classe Startup para configurar o middleware e conterá um método Configuration com um parâmetro do tipo IAppBuilder, conforme a Listagem 4.

Listagem 4. Classe Startup

public class Startup
  {
          public void Configuration(IAppBuilder app)
          {
              
          }
  }

Para configurar toda a requisição a partir da classe Start teremos que considerar os seguintes itens:

  1. Como referenciamos a DLL Microsoft.Owin.Host.SystemWeb a partir do pacote Microsoft.Owin.Host.SystemWeb, por convenção, o método Configuration da classe Start será executada automaticamente;
  2. Precisamos configurar toda a requisição a partir do parâmetro app do método Configuration;
  3. A princípio, para configurar os Middlewares, utilizaremos o método de extensão CreatePerOwinContext que foi disponibilizado pela DLL Microsoft.AspNet.Identity.Owin, do pacote baixado via nuget Microsoft.AspNet.Identity.Core,
  4. Um contexto Owin (OwinContext) será criado e este contexto disponibilizará os objetos nele inserido no método Configuration da classe Startup.

O código então ficará conforme a Listagem 5.

Listagem 5. Classe Startup

public class Startup
  {
          public void Configuration(IAppBuilder app)
          {
              app.CreatePerOwinContext(Contexto.Create);
   
          }
  }

Note, pela Figura 8, que existem inúmeros métodos que podemos utilizar para configurar a requisição do usuário, desde a configuração de classes Managers até itens de autenticação e autorização do usuário. Como queremos configurar a classe UserAppManager para cada requisição e deixá-lo no contexto do Owin, então usaremos o método app.CreatePerOwinContext.

Métodos
da classe UserAppManager

Figura 8. Métodos da classe UserAppManager

Analisando a assinatura do método app.CreatePerOwinContext, conforme a Listagem 6, note que ele espera um delegate.

Listagem 6. Método app.CreatePerOwinContext

public static IAppBuilder CreatePerOwinContext<T>(this IAppBuilder app, 
  Func<Microsoft.AspNet.Identity.Owin.IdentityFactoryOptions<T>, Microsoft.Owin.IOwinContext, T> 
  createCallback) where T : class, IDisposable;

Este delegate será expresso conforme o código a seguir:

public static UserAppManager Create(IdentityFactoryOptions<UserAppManager> options, IOwinContext context) { }

Note que estamos passando o contexto do Owin nos parâmetros do método Create e, como já configuramos o IOwinContext para “carregar” o contexto do EF na classe StartUp, então ele não virá vazio.

Para conseguir gerenciar a classe UserAppManager precisamos de uma classe que implemente IUserStore (ver Figura 5), então vamos analisar a classe UserStore, que é uma implementação de IUserStore, conforme a Figura 9.

Classe
UserStore

Figura 9. Classe UserStore

Note que essa classe contém um construtor do tipo DbContext, logo, se passarmos o contexto do EF disponibilizado pelo IOwinContext configurado na classe Startup, poderemos criar o objeto UsuarioManager, conforme a Listagem 7.

Listagem 7. Objeto UsuarioManager

public static UsuarioManager Create(IdentityFactoryOptions<UsuarioManager> options, IOwinContext context)
  {
              var appcontext = context.Get<Contexto>();
              var usuarioManager = new UserAppManager (new UserStore<Usuario>(appcontext));
   
              return usuarioManager;
  }

O código completo da classe UserAppManager ficará como na Listagem 8.

Listagem 8. Classe UserAppManager

public class UsuarioAppManager : UserManager<Usuario>
      {
          public UsuarioManager(IUserStore<Usuario> store) : base(store)
          {
              
          }
   
          public static UsuarioManager Create(IdentityFactoryOptions<UsuarioManager> options, IOwinContext context)
          {
              var appcontext = context.Get<Repositorio.Contexto>();
   
              var usuarioManager = new UsuarioManager(new UserStore<Usuario>(appcontext));
   
              return usuarioManager;
          }
      }

E a classe Startup completa ficará conforme a Listagem 9.

Listagem 9. Classe Startup completa

public class Startup
  {
          public void Configuration(IAppBuilder app)
          {
              app.CreatePerOwinContext(Contexto.Create);
              app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);           
          }
  }

A classe UserManager contém algumas propriedades e alguns métodos virtuais que podem ser sobrescritos, conforme a Figura 10. Alguns dos exemplos são: política de senha, número máximo de tentativas, período de expiração do Login, criação de usuário entre outros.

Propriedades da classe UserManager

Figura 10. Propriedades da classe UserManager

Agora criaremos um Controller e um usuário no banco a partir do UserAppManager criado anteriormente. Para este fim, iremos até a pasta Controllers e adicionaremos um novo Controller do tipo MVC 5 Controller – Empty, com o nome HomeController, conforme a Figura 11.

Novo controller

Figura 11. Novo controller

A maioria das classes do framework Identity foi feita para se trabalhar de forma assíncrona, logo, construiremos uma View Index que retorna uma Task<ActionResult >, conforme a Listagem 10.

Listagem 10. Classe HomeController

public class HomeController : Controller
      {
          // GET: Home
          public async Task<ActionResult> Index()
          {
              // Contexto Global
              var contexto = HttpContext.GetOwinContext();
              
              // UserManager disponibilizado no contexto
              var manager =  contexto.GetUserManager<UserAppManager>();
   
              // Usuario - classe filha de IdentityUser
              var usuario = new Usuario()
              {
  UserName = "ffonseca",
                  FirstName = "Fábio",
                  LastName = "Fonseca",
                  Email = "fabison@ig.com.br"
                };
   
              // Método disponibilizado pela classe UserManager
              await manager.CreateAsync(usuario, "123Trocar@@");
          
              return View();
          }
      } 

Podemos ver que o objeto HttpContext fornece o contexto do Owin, que fornece inúmeros métodos para facilitar a integração das classes do Identity. Executando o projeto e verificando o banco de dados, podemos notar que foi criado o nosso usuário, com os dados fornecidos pela Controller Home. Observe a Figura 12.

Criação do usuario

Figura 12. Criação do usuario

Autenticação e Autorização

Primeiramente, para que possamos entender melhor o processo de autenticação e autorização, precisamos entender o conceito de duas classes pertencentes ao Namespace System.Security.Principal, que são:

  1. IIdentity – Basicamente contém o nome do usuário autenticado e o tipo de autenticação que está sendo usado (cookieAutentication, TokenAutentication entre outros);
  2. IPrincipal – Contém a informação sobre permissões e autorização do usuário no contexto que ele está inserido.

Para exemplificar estas classes iremos analisar o processo de autenticação feito antes do Owin, que era a autenticação baseada em Forms, ou seja, forms autentication, e a usada com o Identity, que é a Owin forms Authetication. Vale ressaltar que a autenticação via Owin dá suporte a Claims, fato que não ocorria anteriormente.

O processo de autenticação usando o Cookie é basicamente o seguinte: o usuário faz login no sistema e então é criado um cookie criptografado que contém toda a informação do usuário. Este é usado toda vez que o usuário necessite entrar em alguma página que necessite de alguma permissão, facilitando o processo, pois o sistema não precisa consultar a base de dados toda vez que ele for navegar no sistema. Quando o usuário faz o logon no sistema o cookie é removido, conforme vemos no esquema da Figura 13.

Esquema do uso do cookie

Figura 13. Esquema do uso do cookie

Para finalizar a parte teórica vamos analisar algumas diferenças entre Forms Authentication e OWIN Forms Authentication com a Tabela 1.

Features ASP.NET Forms Authentication OWIN Forms Authentication
Cookie Authentication Yes Yes
Cookieless Authentication Yes No
Expiration Yes Yes
Sliding Expiration Yes Yes
Token Protection Yes Yes
Claims Support No Yes
Web Farm Support Yes Yes
Unauthorized Redirection Yes Yes

Tabela 1. Comparativo entre os tipos de autenticação

Forms Autentication

Neste contexto o framework .NET oferece muitos recursos para a criação da identidade do usuário e, para exemplificar isto, vamos mostrar como autenticar e criar algumas roles.

Vamos então configurar o web.Config inserindo o elemento autentication no node system.web, com o modo de autenticação do tipo Forms e o nome do cookie .ASPXFORMSAUTH , conforme o código a seguir:

<authentication mode="Forms">
  <forms name=".ASPXFORMSAUTH"></forms>
  </authentication>

Note que podemos configurar muito mais itens, conforme mostra a Figura 14.

Outras
opções de configuração

Figura 14. Outras opções de configuração

Para o processo de autenticação, o Assembler System.web e o namespace System.Web.Security oferecem uma classe FormsAuthentication utilizada para facilitar o processo de Login e Logon. Para exemplificar o processo de login vamos criar um Controller HomeController e fazer o login do usuário, conforme o código da Listagem 11.

Listagem 11. Controller HomeController

public class HomeController : Controller
      {
          // GET: Default
          public ActionResult Index()
          {
              //regra genérica só pra exemplificar!            
              bool usuarioValido = true;
   
              if (usuarioValido){
                  FormsAuthentication.SetAuthCookie("ffonseca", true);
              }
              
              return View();
          }
      }

Neste processo foi criado um cookie criptografado que contém o nome do usuário e algumas informações que ficarão disponíveis em um objeto global chamado HttpContext. Para exemplificar que o usuário esta autenticado, vamos criar a classe TestController e decorá-la com o atributo Autorize - note, conforme a Figura 15, que ao consultarmos esta página, nenhum erro ocorre.

Classe
TestController

Figura 15. Classe TestController

Note também que o objeto HttpContext “carrega” uma classe do tipo System.Web.Security.Principal.GenericPrincipal (User) que contém um objeto Identity contendo o nome do usuário, o tipo de autenticação e se o usuário está ou não autenticado.

Agora se fizermos logon a partir do método FormsAuthentication.SignOut() e tentarmos entrar na página Test, um erro 404 será disparado, conforme a Figura 16. Observe que algumas configurações já estão pré-configuradas, como por exemplo, a página de redirecionamento, que neste caso é login.aspx.

Erro
404

Figura 16. Erro 404

Em alguns casos precisamos autenticar um grupo de usuários utilizando Roles. Uma forma de relacionar uma role a um usuário é adicionando-a, mas não basta apenas modificar o principal do usuário, também teremos que modificar o cookie criado.

Sabemos que o Pipeline do System.web nos fornece inúmeros eventos, então vamos utilizar o evento AuthorizeRequest para construir a Role e relacioná-la ao usuário autenticado. Para este fim, vamos até o Global.asax e criar um método Application_OnAuthorizeRequest para então criar a Role, conforme a Listagem 12.

Listagem 12. Método Application_OnAuthorizeRequest

public class MvcApplication : System.Web.HttpApplication
      {
          protected void Application_Start()
          {
              AreaRegistration.RegisterAllAreas();
              RouteConfig.RegisterRoutes(RouteTable.Routes);
          }
   
          public void Application_OnAuthorizeRequest()
          {
   
              var cookie = FormsAuthentication.FormsCookieName;
   
              if (cookie == null)
                  return;
   
              HttpCookie httpCookie = Context.Request.Cookies[cookie];
   
              if (httpCookie == null)
                  return;
   
              FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(httpCookie.Value);
   
              FormsIdentity identity = new FormsIdentity(ticket);
   
              GenericPrincipal principal = new GenericPrincipal(identity, new[] { "role1" });
   
              HttpContext.Current.User = principal;
          }
      } 

Para explicar o código apresentado, vamos debugá-lo. Inicialmente note que o nome do cookie é igual aquele configurado no Web.config, como mostra a Figura 17.

Nome
do cookie

Figura 17. Nome do cookie

Com o nome do Cookie podemos consultar o seu valor, conforme a Figura 18.

Valor
do cookie

Figura 18. Valor do cookie

Após consultá-lo iremos descriptografá-lo (Figura 19). Crie um objeto que associe o usuário atual às roles criadas: para este fim usamos a classe GenericPrincipal e, após esta etapa, associamos esta ao contexto, como mostra a Figura 20.


Figura 19. Descriptografando o cookie

Classe
GenericPrincipal

Figura 20. Classe GenericPrincipal

Para testar a role vamos até a Controller Test e decorá-la, conforme a Listagem 13.

Listagem 13. Controller Test

    [Authorize(Roles="role1")]
      public class TestController : Controller
      {
          // GET: Test
          public ActionResult Index()
          {
              var user = HttpContext.User;
              
              return View();
          }
      }

Testando a classe TestController, note que nenhum erro ocorreu, conforme a Figura 21.

Classe
TestController

Figura 21. Classe TestController

Se tirarmos a role do usuário e tentarmos acessar a classe TestController ocorrerá um erro 404, como mostra a Figura 22.

Erro 404 na Classe TestController

Figura 22. Erro 404 na Classe TestController

OWIN Forms Authentication

O Owin trabalha com Middlewares, então para criar uma política de segurança precisamos criar ou baixar um pacote já pronto com um middleware de autenticação.

Neste artigo usaremos um método de autenticação baseado em cookies e também geraremos uma identidade no sistema para o usuário. Como foi feito no Forms authentication, também podemos definir algumas configurações no processo de autenticação, como por exemplo, o local onde o usuário deverá ser redirecionado. Caso ele ainda não esteja logado, o tempo de expiração do login, o nome do Cookie, etc, ou seja, o conceito é o mesmo do Forms autentication, descrito no tópico anterior. O que muda é que antes uma grande parte da configuração era no Web.Config e agora são a partir de propriedade de classes fornecidas pelo framework Identity.

Sendo assim, no método Configuration configuraremos o modo de autenticação usando uma implementação da classe SignInManager, usada para facilitar o login do usuário, e para configurar os elementos de autenticação iremos usar a classe CookieAuthenticationOptions.

Como o Owin é baseado em middlewares, iremos usar novamente o método CreatePerOwinContext para que a interfase IOwinContext contenha a implementação da classe SignInManager em memória. Mas antes de construir o objeto que irá implementar a classe SignInManager vamos analisar a classe SignInManager, descrita na Figura 23.

Classe
SignInManager

Figura 23. Classe SignInManager

Note que a classe SignInManager contém um construtor com os parâmetros UserManager (já criado) e a interface authenticationManager, o qual pode ser resgatado no contexto do Owin. Logo a classe ficará igual a Listagem 14.

Listagem 14. Classe SignInManager

public class AppSignInManager : SignInManager<Usuario, string>
  {
  public AppSignInManager(AppUserManager userManager, IAuthenticationManager authenticationManager) : base(userManager, authenticationManager)
          {
   
  }
   
  public static AppSignInManager Create(IdentityFactoryOptions<AppSignInManager> option, IOwinContext context)
          {
              var manager = context.GetUserManager<AppUserManager>();
   
              var sign = new AppSignInManager(manager, context.Authentication);
   
              return sign;
          }
  }

Note que criamos o método Create que retorna o objeto AppSignInManager. Utilizando novamente o método CreatePerOwinContext para deixar a classe AppSignInManager no contexto do Owin, a classe Startup ficará conforme a Listagem 15.

Listagem 15. Nova configuração da classe Startup

public class Startup
  {
          public void Configuration(IAppBuilder app)
          {
              app.CreatePerOwinContext(Contexto.Create);
              app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
              app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);
              
              app.UseCookieAuthentication(new CookieAuthenticationOptions
              {
                  AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                  LoginPath = new PathString("/Account/Login"),
                  CookieName = "Devimedia",
                  CookiePath = "/"
              });
          }
  }

Usamos o método UseCookieAuthentication para definir o método de autenticação passando o objeto CookieAuthenticationOptions para definir algumas propriedades.

Para criar o login vamos criar uma view chamada Login o qual irá autenticar o usuário, conforme a Listagem 16.

Listagem 16. View Login

public async Task<ActionResult> Login()
          {
              var userManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
   
              var user = await userManager.FindAsync("ffonseca", "123Trocar@@"); 
              
              var appAsign = HttpContext.GetOwinContext().Get<AppSignInManager>();
   
              appAsign.SignIn(user, true, true);
              
              return View();
          } 

Note que selecionamos o usuário criado anteriormente e, a partir do método SignIn, disponibilizado pelo manager AppSignInManager, autenticamos o usuário ffonseca. Para testar se funcionou, vamos criar uma view chamada “Autorizado” e decorá-la com a propriedade Authorize e executar o projeto.

Debugando-o, veremos a autenticação do usuário na Figura 24.

Autenticação do usuário

Figura 24. Autenticação do usuário

Note que se navegarmos até página “Autorizado” verificamos que um cookie foi criado com o nome “Devimedia”, o qual foi configurado na classe Startup, como mostra a Figura 25.

Cookie
criado na página Autorizado

Figura 25. Cookie criado na página Autorizado

Observando mais afundo, note que uma identidade foi associada ao usuário, como mostra a Figura 26.

Identidade
associada ao usuário

Figura 26. Identidade associada ao usuário

Logo o código inteiro ficaria como na Listagem 17.

Listagem 17. Código da página de login

public async Task<ActionResult> Login()
          {
              var userManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
   
              var user = await userManager.FindAsync("ffonseca", "123Trocar@@"); 
              
              var appAsign = HttpContext.GetOwinContext().Get<AppSignInManager>();
   
              appAsign.SignIn(user, true, true);
              
              return View();
          }
   
          [Authorize]
          public ActionResult Autorizado()
          {
              HttpCookie cookie = HttpContext.Request.Cookies["Devimedia"];
   
              IPrincipal user = HttpContext.User;
   
              return View();
  }

Para finalizar essa etapa vamos demonstrar como as roles são criadas. Por padrão, vamos criar uma implementação de um objeto que gerencie as roles (RoleManager) e adicioná-la no contexto do Owin, a partir da classe Startup. A classe criada ficará conforme a Listagem 18.

Listagem 18. RoleManager

public class AppRoleManager : RoleManager<IdentityRole>
      {
          public AppRoleManager(IRoleStore<IdentityRole, string> store)
              :base(store)
          {
          }
   
  public static AppRoleManager Create(IdentityFactoryOptions<AppRoleManager> options, IOwinContext context)
          {
              return new AppRoleManager(new RoleStore<IdentityRole>(context.Get<Contexto>()));
          }
  }

Note que o processo é análogo à criação das classes AppUserManager e AppSignInManager, então na classe Startup teremos o seguinte código da Listagem 19.

Listagem 19. Classe Startup com as novas classes

public class Startup
  {
          public void Configuration(IAppBuilder app)
          {
              app.CreatePerOwinContext(Contexto.Create);
              app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
              app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);
              app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);
   
              app.UseCookieAuthentication(new CookieAuthenticationOptions
              {
                  AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                  LoginPath = new PathString("/Account/Login"),
                  CookieName = "Devimedia",
                  CookiePath = "/"
              });
          }
  }

Iremos também criar duas Views: a primeira para criar a role e a segunda para testar se a mesma foi criada, conforme a Listagem 20.

Listagem 20. Criação da Role

public async Task<ActionResult> Role()
          {
   
              var appRole = HttpContext.GetOwinContext().Get<AppRoleManager>();
   
              var  role = new IdentityRole("Devimedia");
   
              await appRole.CreateAsync(role);
   
              var userManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
   
              var user = await userManager.FindAsync("ffonseca", "123Trocar@@");
   
              await userManager.AddToRoleAsync(user.Id, role.Name);
              
              return View();
          }
   
          [Authorize(Roles = "Devimedia")]
          public ActionResult TestarRole()
          {
              return View();
  }

Debugando o código temos a criação da Role Devimedia e sua associação ao usuário, como mostra a Figura 27.

Criação
da Role Devimedia

Figura 27. Criação da Role Devimedia

Note que o usuário pertence a role Devimedia, como na Figura 28.

Role
Devimedia

Figura 28. Role Devimedia

Note também que se verificarmos na Figura 29 a role criada e na Figura 30 a role associada ao usuário.

Criação
da Role

Figura 29. Criação da Role

Associação da Role ao usuário

Figura 30. Associação da Role ao usuário

Embora este artigo mostre uma pequena introdução ao ASP.NET Identity, podemos concluir que ele contém inúmeras propriedades e funcionalidades.

Bibliografia

[1] ASP.NET Identity
https://aspnetidentity.codeplex.com/wikipage?title=Roadmap

[2] Autenticação de formulários no MVC 5
http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc-5.aspx

[3] Microsoft.AspNet.Identity Namespace
https://msdn.microsoft.com/en-us/library/microsoft.aspnet.identity(v=vs.108).aspx