Jump to content

Erro 401 ao Consumir API com Token de Autenticação no .NET MVC - Solução?


Postagens Recomendadas

image.png

 

Boa noite, devs! Estou consumindo uma WEB API com .NET usando REST. A API funciona perfeitamente quando eu a testei no postman. No entanto, ao consumi-la, eu recebo esse erro 401 no navegador que significa não autorizado.

 

Eu consigo fazer com ele obtenha o token, mas ele não está indo para o cabeçalho de autorização de jeito nenhum. Observem o código.

 

Código da aplicação MVC:

 

Program.cs

using CreativeMultiCoisasMVC.Repositories.Interfaces;
using CreativeMultiCoisasMVC.Repositories;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;


var builder = WebApplication.CreateBuilder(args);


builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidAudience = "CreativeService",
            
        };
    });

// Add services to the container.


builder.Services.AddControllersWithViews();

builder.Services.AddTransient<IProdutoRepository, ProdutoRepository>();


builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(5); 
    
});

builder.Services.AddHttpContextAccessor();
builder.Services.AddLogging();

builder.Services.AddHttpClient();


var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");

    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseSession();

app.UseEndpoints(endpoints =>

app.UseEndpoints(endpoints =>
{
    //endpoints.MapControllerRoute(
    //     name: "areas",
    //     pattern: "{area:exists}/{controller=Admin}/{action=Index}/{id?}"
    // );

    endpoints.MapControllerRoute(
        name: "categoriaFiltro",
        pattern: "Produto/{action}/{categoria?}",
        defaults: new { Controller = "Produto", action = "List" });


    endpoints.MapControllerRoute(
     name: "default",
     pattern: "{controller=Home}/{action=Index}/{id?}");
}));


app.Run();

 

 

 

Código do controlador MVC:

 

public class ProdutoController : Controller
{
    private readonly HttpClient _httpClient;
    private readonly IProdutoRepository _produtoRepository;
    public ProdutoController(HttpClient httpClient, IProdutoRepository produtoRepository)
    {
        _httpClient = httpClient;
        _produtoRepository = produtoRepository;
    }

    
    [Authorize]
    public async Task<IActionResult> List(string categoria)
    {
        IEnumerable<ProdutoViewModel> produtos;
        string categoriaAtual = string.IsNullOrEmpty(categoria) ? "Todos os produtos" : categoria;
        string descricaoCategoriaAtual = string.Empty;

        try
        {
            
            produtos = await _produtoRepository.GetProdutosAsync();

            if (!string.IsNullOrEmpty(categoria))
            {
                produtos = await _produtoRepository.GetProdutosPorCategoriaAsync(categoria);

                // Obtém a descrição da categoria a partir da resposta da API
                var categoriaResponse = await _httpClient
                    .GetAsync($"api/categoria/searchCategoria?nome={categoria}"); // Use o caminho relativo

                if (categoriaResponse.IsSuccessStatusCode)
                {
                    var categoriaData = await categoriaResponse.Content.ReadFromJsonAsync<CategoriaViewModel>();
                    descricaoCategoriaAtual = categoriaData?.Descricao;
                }
            }
        }
        catch
        {
            produtos = new List<ProdutoViewModel>();
        }

        var produtoViewModel = new ProdutoListViewModel
        {
            Produtos = produtos,
            CategoriaAtual = categoriaAtual,
            DescricaoCategoriaAtual = descricaoCategoriaAtual
        };

        return View(produtoViewModel);
    }

//...

}

 

public class AccountController : Controller
{
    private readonly IConfiguration _configuration;
    private readonly HttpClient _httpClient;

    public AccountController(HttpClient httpClient, IConfiguration configuration)
    {
        _configuration = configuration;
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri(_configuration["ApiBaseUrl"]);
    }

 

//...
    [AllowAnonymous]
    [HttpGet]
    public IActionResult Login(string returnUrl)
    {
        return View(new LoginViewModel() { ReturnUrl = returnUrl });
    }

    [AllowAnonymous]
    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            var token = await GetApiAuthTokenAsync(model);

            if (!string.IsNullOrEmpty(token))
            {
                //Armazena o tokrn na sessão
                HttpContext.Session.SetString("AuthToken", token);

                // Adicione o token de autorização ao HttpClient
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

                return RedirectToAction("List", "Produto");
            }
            else
            {
                ModelState.AddModelError("", "Credenciais inválidas!");
            }
        }

        return View(model);
    }

    public async Task<string> GetApiAuthTokenAsync(LoginViewModel model)
    {
        var loginRequest = new
        {
            userName = model.UserName,
            password = model.Password,
        };

        var token = await SendPostRequest("/api/account/login", loginRequest);

        return token;
    }

    private async Task<string> SendPostRequest(string requestUri, object requestData)
    {
        var jsonContent = JsonConvert.SerializeObject(requestData);
        var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

        var response = await _httpClient.PostAsync(requestUri, content);

        if (response.IsSuccessStatusCode)
        {
            return await response.Content.ReadAsStringAsync();
        }
        else
        {
            return null;
        }
    }
}
 

 

 

Código da API:

 

Program.cs

 

using System.Text;
using CreativeMultiCoisas.Context;
using CreativeMultiCoisas.Models;
using CreativeMultiCoisas.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>(options =>
       options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));


builder.Services.AddIdentity<IdentityUser, IdentityRole>()
       .AddEntityFrameworkStores<AppDbContext>()
       .AddDefaultTokenProviders();

builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped(sp => CarrinhoCompra.GetCarrinho(sp));

builder.Services.AddCors();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(4);

});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var secretKey = builder.Configuration.GetSection("AppSettings:SecretKey").Value;
var audience = "CreativeService";
builder.Services.AddSingleton(new TokenService(secretKey, audience));
// Converte a chave secreta lida em bytes
var keyBytes = Encoding.UTF8.GetBytes(secretKey);
var chaveCriptografada = new SymmetricSecurityKey(keyBytes);

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = chaveCriptografada,
            ValidAudience = "CreativeService",
        };
    });

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}


app.UseAuthentication();

app.UseAuthorization();

app.UseCors(c =>
{
    c.AllowAnyHeader();
    c.AllowAnyMethod();
    c.AllowAnyOrigin();
});


app.UseHttpsRedirection();

app.UseSession();

app.MapControllers();

app.Run();
 

Controlador produto da API:

 

[Route("api/[controller]")]
[ApiController]
public class ProdutoController : ControllerBase
{
    private readonly AppDbContext _context;

    public ProdutoController(AppDbContext context)
    {
        _context = context;
    }

    [Authorize(AuthenticationSchemes = "Bearer")]
    [HttpGet("obterProduto")]
    public async Task<ActionResult<IEnumerable<ProdutoDTO>>> GetProdutos()
    {
        var produtos = await _context.Produtos
            .Include(p => p.Categoria)
            .Select(p => new ProdutoDTO
            {
                ProdutoId = p.ProdutoId,
                Nome = p.Nome,
                DescricaoCurta = p.DescricaoCurta,
                DescricaoDetalhada = p.DescricaoDetalhada,
                Preco = p.Preco,
                ImagemUrl = p.ImagemUrl,
                ImagemThumbnailUrl = p.ImagemThumbnailUrl,
                IsPromocao = p.IsPromocao,
                EmEstoque = p.EmEstoque,
                CategoriaDTO = new CategoriaDTO
                {
                    CategoriaId = p.CategoriaId,
                    CategoriaNome = p.Categoria.CategoriaNome,
                    Descricao = p.Categoria.Descricao
                },
            })
            .ToListAsync();

        return produtos;
    }
}

 

 

Controlador account da API

 

[Route("api/[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;
    private readonly TokenService _tokenService;

    public AccountController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager, TokenService tokenService)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _tokenService = tokenService;
    }


    [AllowAnonymous]
    [HttpPost("register")]
    public async Task<IActionResult> Register([FromBody] RegisterDTO model)
    {
        if (ModelState.IsValid)
        {
            var existingUser = await _userManager.FindByNameAsync(model.UserName);
            if (existingUser != null)
            {
                return BadRequest("Nome de usuário já está em uso.");
            }

            existingUser = await _userManager.FindByEmailAsync(model.EmailRegister);
            if (existingUser != null)
            {
                return BadRequest("Endereço de e-mail já está em uso.");
            }

            var user = new IdentityUser { UserName = model.UserName, Email = model.EmailRegister };
            var result = await _userManager.CreateAsync(user, model.Password);

            if (result.Succeeded)
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return Ok("Registro bem-sucedido.");
            }
            else
            {
                return BadRequest(result.Errors);
            }
        }

        return BadRequest(ModelState);
    }

    [AllowAnonymous]
    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginDTO model)
    {
        if (ModelState.IsValid)
        {
            var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, isPersistent: false, lockoutOnFailure: false);

            if (result.Succeeded)
            {
                // Gere um token JWT usando o serviço
                var token = _tokenService.GenerateToken(model.UserName, _tokenService.SecretKey, 4);
                
                HttpContext.Response.Headers.Add("Authorization", $"Bearer {token}");

                //return Ok(new
                //{
                //    Token = token,
                //    Message = "Login bem-sucedido."
                //});

                return Ok(token);
            } 
            else
            {
                return BadRequest("Login falhou. Verifique suas credenciais.");
            }
        }

        return BadRequest(ModelState);
    }


    [Authorize(AuthenticationSchemes = "Bearer")]
    [HttpPost("logout")]
    public async Task<IActionResult> Logout()
    {
        HttpContext.Session.Clear();
        HttpContext.User = null;
        await _signInManager.SignOutAsync();
        return Ok("Logout bem-sucedido.");
    }
}
 

Esse é o código. Vale lembrar que o token obtido é válido e funciona na API. Porém ao consumi-la e tentar mandar o token no cabeçalho de autorização, eu recebo esse erro 401(não autorizado) como pode ver na imagem. É isso, e esperem que me ajudem. Desde já agradeço.

Link to comment
Compartilhe em outros sites

  • Douglas Garcia mudou o título para Erro 401 ao Consumir API com Token de Autenticação no .NET MVC - Solução?

Crie uma conta ou entre para comentar 😀

Você precisa ser um membro para deixar um comentário.

Crie a sua conta

Participe da nossa comunidade, crie sua conta.
É bem rápido!

Criar minha conta agora

Entrar

Você já tem uma conta?
Faça o login agora.

Entrar agora


×
×
  • Create New...