ASP.NET Core 3.1 - CRUD : Web API com EF Core e Tokens JWT


Hoje teremos um roteiro básico para criar Web APIs para realizar o CRUD com ASP .NET Core 3.1 e EF Core usando Tokens JWT.

Continuando a quarta parte do artigo vamos implementar a Autenticação baseada no token Jwt ou Bearer Authentication.

Implementando a Autenticação : Bearer Authentication

Já definimos um usuário para acessar a API, e implementamos a geração do Token Jwt com base nas credenciais do usuário registrado na tabela Usuarios.

Precisamos agora proteger a nossa API ou seja o nosso endpoint de forma que somente usuários autenticados e que possuam o token Jwt possam acessar a nossa API.

Para isso vamos implementar em nossa aplicação a autenticação Jwt ou Bearer Authentication, assim poderemos enviar o token cifrado que será decifrado em cada requisição e assim poderemos acessar o endpoint da API.

Começamos informando ao ASP .NET Core para ativa a autenticação no método ConfigureServices da classe Startup:

public void ConfigureServices(IServiceCollection services)
{
   services.AddDbContext<AppDbContext>(options =>
   {
       options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
   });
   services.AddScoped<IProdutoRepository, ProdutoRepository>();
   services.AddControllers();
   services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
   {
       options.RequireHttpsMetadata = false;
       options.SaveToken = true;
       options.TokenValidationParameters = new TokenValidationParameters()
       {
           ValidateIssuer = true,
            ValidateAudience = true,
            ValidAudience = Configuration["Jwt:Audience"],
            ValidIssuer = Configuration["Jwt:Issuer"],
             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]));
          };
      });
  }

Neste código:

- Adicionamos o serviço de Autenticação no IServicesCollection informando o seu tipo (bearer),  e, passamos a chave de segurança usada quando criamos o token jwt.

- Habilitamos a validação da Audience e do Issuer, obtendo os valores definidos no arquivo de configuração;

- Definimos SaveToken igual a true e com isso o token será armazenado no contexto HTTP e poderemos acessar o token no controller quando precisarmos;

Concluindo a configuração da autenticação na ASP .NET Core vamos agora habilitar a autenticação no método Configure:

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseStatusCodePages();
                app.UseDeveloperExceptionPage();
            }
            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseAuthentication();

            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
       }

Aproveitei e também habilitei a exibição dos códigos de status das páginas quando ocorrem erros para o ambiente de desenvolvimento.

Finalmente temos tudo pronto para poder proteger a nossa API de acesso não autorizado.

Como fazemos isso ?

Podemos usar os atributos de autorização a seguir:

Então vamos fazer o seguinte:

- Vamos aplicar o atributo [Authorize] ao controlador ProdutosController de forma que somente quem estiver autenticado poderá acessar a nossa API;

- Vamos criar um método HttpGet que retorna apenas a data e hora de acesso feito à API e vamos aplicar a esse método Action o atributo [AllowAnonymous], assim qualquer um vai poder acessar este método da API;

- Vamos alterar a rota do método HttpGet que retorna todos os produtos para [HttpGet("todos")] assim para acessar este método Action teremos que usar o endpoint api/produtos/todos;

Após estas alterações o código(simplificado) do controlador ProdutosController ficou assim:

    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class ProdutosController : Controller
    {
        private readonly IProdutoRepository repository;
        public ProdutosController(IProdutoRepository _context)
        {
            repository = _context;
        }
        [AllowAnonymous]
        [HttpGet]
        public ActionResult<string> Get()
        {
            return "ProdutosController ::  Acessado em  : " + DateTime.Now.ToLongDateString();
        }
        [HttpGet("todos")]
        public async Task<ActionResult<IEnumerable<Produto>>> GetProdutos()
        {
            var produtos = await repository.GetAll();
            if (produtos == null)
            {
                return BadRequest();
            }
            return Ok(produtos.ToList());
        }
        ...
    }

Agora é só alegria...

Vamos testar o acesso à nossa API fazendo o acesso sem autenticação e a seguir vamos obter o token e fazer o acesso usando o Token.

1- Executando o projeto inicialmente teremos acesso ao endpoint api/produtos que aciona o método HttpGet e exibe a data de acesso à API :

Como este método Action foi decorado com o atributo [AllowAnonymous] qualquer usuário acessa este endpoint.

2- Vamos tentar acessar agora o método que retorna todos os produtos sem o token. Vamos digitar no navegador a url : https://localhost:44344/api/produtos/todos

Observe que obtemos um 401 ou seja acesso não autorizado.

3- Vamos agora tentar o acesso sem usar o token para retornar todos os produtos

Naturalmente obtemos o mesmo resultado pois nossa API esta protegida e precisamos gerar o token para acessar os demais métodos Action.

4- Vamos então gerar o Token para poder acessar a API:

Como usamos o token gerado ?

Basta copiar o token e definir uma nova requisição GET para acessar todos os produtos usando o endpoint : https://localhost:44344/api/produtos/todos e

 Ao clicar no botão SEND teremos no response o retorno de todos os produtos:

Quando passamos o cabeçalho da autorização com o token Jwt para a API, o middleware de autenticação analisa e valida o token. Se ele for considerado válido, a propriedade UIdentity.IsAuthenticated será definida como true.

O atributo [Authorize] incluído no controlador verificará se a requisição está autenticada, e , se isso for verdade, a API poderá ser acessada.  Se UIdentity.IsAuthenticated retornar false, será retornado um erro 401 não autorizado.

Você poderá testar os outros endpoints e verá que com o token o acesso será permitido.

Em anexo esta o projeto original, extraia o projeto, altere a string de conexão no arquivo appsettings.json para usar o SQL Server no seu ambiente. Crie as tabelas usadas conforme mostrado no artigo e execute o projeto.

Pegue o projeto aqui:  InventarioNET.zip  (sem as referências)

"Porque o Filho do homem (Jesus) veio buscar e salvar o que se havia perdido."
Lucas 19:10

Referências:


José Carlos Macoratti