Autenticação com ASP.NET Core 2.0 com Razor Pages

0

Trabalhar com identidade e autenticação dentro do ASP.NET Core é um sistema de associação que permite que você adicionar a funcionalidade de logon ao seu aplicativo. Recentemente eu escrevi uma pequena aplicação já utilizando o Razor pages

Você pode configurar a identidade do ASP.NET Core para usar um banco de dados para armazenar os nomes de usuário, senhas e dados de perfil. Como alternativa, você pode usar seu próprio armazenamento persistente, no exemplo abaixo eu foquei principalmente na autenticação como um todo, e não fiz persistência a dados para deixarmos o artigo bem focado em autenticação.

Primeiramente, vamos criar um projeto do Asp.NET Core 2.0 com Razor Pages:

 

Após a criação do projeto, a estrutura de pastas da solução será a seguinte:

Note que eu criei duas pastas, Model e Service, onde eu criei as respectivas classes:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AuthCookie.Model
{
    public class User
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string Token { get; set; }
        public string Password { get; set; }
        public string PasswordHash { get; set; }
        public DateTime CreateDate { get; set; }
    }
}

 

 using AuthCookie.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AuthCookie.Service
{
    public interface IUserService
    {
        User Authenticate(string email, string password);
    }

    public class UserService : IUserService
    {
        public User Authenticate(string email, string password)
        {
            if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
                return null;

            User user = new User { Email = email, Token = "Token", Name = "Usuário Codigo Simples" };

            return user;
        }
    }
}

 

Com isto, dentro da minha página Index, eu criei um formulário simples, onde eu irei chamar o método de autenticação;

 @page
@model IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    ViewData["Title"] = "Home page";
}

<br />
<p>
    @Model.Message
</p>

<p>
    Faça login:
</p>
<div asp-validation-summary="All"></div>
<form method="POST" class="form-group">
    <div>Email: <input asp-for="Customer.Email" type="email" class="input-group" /></div>
    <br />
    <div>Password: <input asp-for="Customer.Password" type="password" class="input-group" /></div>
    <br />
    <input type="submit" class="btn btn-default" />
</form>

 

E agora o codebehind da minha página Index:

 using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AuthCookie.Service;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace AuthCookie.Pages
{
    public class IndexModel : PageModel
    {
        //instanciando uma classe de serviço por injeção
        private IUserService _userService;
        public string Message { get; private set; } = string.Empty;

        public IndexModel(
            IUserService userService
        )
        {
            _userService = userService;
        }

        //fazendo bind da model para ser usada no front-end
        [BindProperty]
        public Model.User Customer { get; set; }


        //metodo Get inicial
        public void OnGet()
        {
            //verifica se o usuário está autenticado
            if (User.Identity.IsAuthenticated)
            {
                Message += "Olá Usuário, você está autenticado";

            }
            else
            {
                Message += "Você não está autenticado";
            }
        }
        
        //metodo post do formulario
        public IActionResult OnPost()
        {
            if (!ModelState.IsValid)
            {
                return RedirectToPage("/Index");
            }

            //faz a busca do usuário e verifica se existe
            var user = _userService.Authenticate(Customer.Email, Customer.Password);

            if (user == null)
                return Unauthorized();

            //declara claim de identidade
            var claim = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, user.Token.ToString())
                });

            var claims = new[]
            {
                 new Claim(ClaimTypes.Email, user.Email.ToString())
            }.ToAsyncEnumerable().ToEnumerable();


            //faz autenticação via Cookie
            var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
            HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
                new ClaimsPrincipal(identity));

            // redireciona para a Index novamente, porém já autenticado
            return RedirectToPage("/Index");
        }
    }
}

 

Com isto vimos que foi necessário apenas dois métodos, o método Get que exibe uma mensagem na página informando se o usuário está logado ou não no sistema; e um método Post que captura as informações do formulário e realiza a autenticação do usuário de fato.

Além disto, precisamos configurar como o sistema irá se comportar com a autenticação, dentro da classe Startup.cs:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AuthCookie.Service;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;

namespace AuthCookie
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddCors();
            //adiciona a classe de serviço ao escopo para utilizarmos na página
            services.AddScoped<IUserService, UserService>();
          
            // configura autenticação por cookie
            services.AddAuthentication(options =>
            {

                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie(o => { o.LoginPath = new PathString("/index"); o.Cookie.Name = "codigosimples"; });

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseCors(x => x
           .AllowAnyOrigin()
           .AllowAnyMethod()
           .AllowAnyHeader()
           .AllowCredentials());

            //adiciona autenticação ao projeto
            app.UseAuthentication();

            app.UseStaticFiles();

            app.UseMvc();
        }
    }
}

E pronto! O sistema de autenticação deve funcionar agora sem maiores problemas. Lembrando que é um sistema simples e básico sem nenhuma validação ainda ou busca de usuário no banco, mas deve lhe ajudar e muito para criar um sistema básico de autenticação.

Todo o código está no meu github: https://github.com/jhomarolo/auth-aspnetcore

Espero que tenham gostado! Um grande abraço a todos!

 

 

Compartilhe.

Sobre o autor

Criador do blog Código Simples e com mais 9 anos de experiência em TI, com títulos de MVP Microsoft na área de Visual Studio Development, Neo4j Top 50 Certificate, Scrum Master e MongoDB Evangelist. Atuando em funções analista, desenvolvedor, arquiteto, líder técnico e gestor de equipes. Mais informações em : http://jhonathansoares.com