Аутентификация ASP.NET Core 8.0 JWT не работает на других контроллерах, кроме контроллера аутентификацииC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Аутентификация ASP.NET Core 8.0 JWT не работает на других контроллерах, кроме контроллера аутентификации

Сообщение Anonymous »

Я столкнулся с проблемой аутентификации JWT в моем приложении ASP.NET Core 8.0. Хотя генерация токена и аутентификация в моем AuthenticationController работают корректно, любые запросы к другим контроллерам, требующие авторизации, возвращают 401 Unauthorized.
Среда:
  • Версия ASP.NET Core: 8.0
  • Среда размещения: Azure
Описание проблемы
Токен JWT создан и успешно проверен в AuthenticationController. Однако когда я пытаюсь получить доступ к другим контроллерам, требующим авторизации, я получаю ответ 401 Unauthorized. Издатель JWT, аудитория и секрет правильно настроены в Azure и успешно используются в AuthenticationController.
В целях тестирования я добавил действие, которое хочу использовать. в другом контроллере (который не работает) внутри AuthenticationController, и он работает даже без атрибута [Authorize] на этом контроллере.

Код: Выделить всё

using Expenses.Data;
using expensesBE.Data.DTO.Interfaces;
using expensesBE.Data.DTO;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Carica le variabili d'ambiente
var jwtIssuer = Environment.GetEnvironmentVariable("JWT_ISSUER");
var jwtSecret = Environment.GetEnvironmentVariable("JWT_SECRET");
var jwtAudience = Environment.GetEnvironmentVariable("JWT_AUDIENCE");

if (string.IsNullOrEmpty(jwtIssuer) || string.IsNullOrEmpty(jwtSecret) || string.IsNullOrEmpty(jwtAudience))
{
throw new ArgumentNullException("JWT configuration is missing");
}

// Costruisci la stringa di connessione
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

// Add services to the container.
builder.Services.AddDbContext(options =>
options.UseSqlServer(connectionString));

// Configura Identity
builder.Services.AddDefaultIdentity(options =>
{
options.SignIn.RequireConfirmedAccount = true;
})
.AddRoles()
.AddEntityFrameworkStores();

// Configura l'autenticazione JWT
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtIssuer,
ValidAudience = jwtIssuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSecret))
};
});

// Aggiungi i servizi personalizzati
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddSingleton();

// Configura CORS
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins",
builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddControllersWithViews();

var app = builder.Build();

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

app.UseSwagger(); // Enable Swagger
app.UseSwaggerUI();  // Enable Swagger UI

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseRouting();

app.UseCors("AllowAllOrigins");

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

app.MapRazorPages();
app.MapControllers();

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

app.Run();

Код: Выделить всё

--using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace expensesBE.Data.DTO.Utilities
{
public static class JwtGenerator
{
public static string GenerateUserToken(string username)
{
var claims = new Claim[]
{
new Claim(ClaimTypes.Name, username),
};

return GenerateToken(claims, DateTime.UtcNow.AddDays(1));
}

private static string GenerateToken(Claim[] claims, DateTime expires)
{
var tokenHandler = new JwtSecurityTokenHandler();
var secret = Environment.GetEnvironmentVariable("JWT_SECRET");
var issuer = Environment.GetEnvironmentVariable("JWT_ISSUER");
var audience = Environment.GetEnvironmentVariable("JWT_AUDIENCE");
var key = Encoding.ASCII.GetBytes(secret);

var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = expires,
Issuer = issuer,
Audience = audience,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};

var token = tokenHandler.CreateToken(tokenDescriptor);

return tokenHandler.WriteToken(token);
}
}
}

Код: Выделить всё

--using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using expensesBE.Models;
using expensesBE.Data;
using System.Threading.Tasks;
using System.Linq;
using expensesBE.Data.DTO;
using Expenses.Data;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;

namespace expensesBE.Controllers
{
[ApiController]
[Route("api/[controller]")]
[Authorize] // Richiede l'autenticazione per tutte le azioni del controller
public class ExpensesController : ControllerBase
{
private readonly AppDbContext _context;

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

// POST: api/expenses
[HttpPost("AddExpense")]
public async Task AddExpense([FromBody] Expense expense)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState); // Ritorna un BadRequest se il modello non è valido
}

var userId = User.FindFirst(ClaimTypes.Name)?.Value ?? User.FindFirst("unique_name")?.Value;
expense.UserId = userId; // Associa l'ID utente alla spesa

_context.Expenses.Add(expense);
await _context.SaveChangesAsync();

return Created("api/expenses/AddExpense", expense); // Ritorna CreatedAtAction
}
}
}

Код: Выделить всё

--using Microsoft.AspNetCore.Mvc;
using expensesBE.Data.DTO.CustomExceptions;
using Microsoft.AspNetCore.Identity;
using expensesBE.Data.DTO.Interfaces;
using expensesBE.Data.DTO;
using Expenses.Data;
using Microsoft.EntityFrameworkCore;
using Expenses.Data; // Aggiungi questo spazio dei nomi
using expensesBE.Models;

namespace expensesBE.Controllers
{
[ApiController]
[Route("[controller]")]
public class AuthenticationController : ControllerBase
{
private readonly IUserService _userService;
private readonly UserManager _userManager;
private readonly AppDbContext _dbContext;

public AuthenticationController(UserManager  userManager, IUserService userService, AppDbContext dbContext)
{
_userManager = userManager;
_userService = userService;
_dbContext = dbContext;
}

[HttpPost("signup")]
public async Task SignUp([FromBody] UserDto userDto)
{
try
{
var result = await _userService.Signup(userDto);

return Created("", result);
}
catch (UsernameAlreadyExistsException e)
{
return StatusCode(409, e.Message);
}
}

[HttpPost("signin")]
public async Task SignIn([FromBody] UserDto userDto)
{
try
{
var result = await _userService.SignIn(userDto);

return Ok(result);
}
catch (InvalidUsernamePasswordException e)
{
return StatusCode(401, e.Message);
}
}

[HttpGet("ConfirmEmail")]
public async Task ConfirmEmail(string userId, string token)
{
if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(token))
{
return BadRequest("UserId and Token are required");
}

var user = await _userManager.FindByIdAsync(userId);

if (user == null)
{
return NotFound("User not found");
}

var result = await _userManager.ConfirmEmailAsync(user, token);

if (result.Succeeded)
{
return Ok("Email confirmed successfully");
}

return BadRequest("Email confirmation failed");
}

[HttpPost("AddExpense")]
public async Task AddExpense([FromBody] Expense expense)
{
if (expense == null)
{
return BadRequest("Expense data is required");
}

// Verifica se l'UserId esiste nella tabella AspNetUsers
var userExists = await _userManager.FindByIdAsync(expense.UserId) != null;

if (!userExists)
{
return BadRequest("The specified UserId does not exist.");
}

// Aggiungi la nuova spesa al contesto del database
await _dbContext.Expenses.AddAsync(expense);
await _dbContext.SaveChangesAsync();

return CreatedAtAction(nameof(AddExpense), new { id = expense.Id }, expense);
}
}
}
Доступ к защищенным конечным точкам: я создал ExpensesController с атрибутом [Authorize] для защиты конечных точек. Я использовал токен для отправки запроса к защищенной конечной точке AddExpense.
Тестирование с помощью Postman: я использовал Postman для отправки запросов к конечной точке AddExpense с помощью JWT. токен, включенный в заголовок авторизации как предъявитель . Несмотря на это, я получил ответ 401 Unauthorized.
Проверка утверждений токена: я проверил токен с помощью jwt.io, чтобы убедиться, что он содержит правильные утверждения и правильно подписан. Согласно веб-сайту, токен действителен.
Альтернативное тестирование: для тестирования я временно переместил действие AddExpense в AuthenticationController и подтвердил, что оно работает без [ Authorize], что указывает на то, что проблема связана с обработкой авторизации, а не с самим токеном.

Подробнее здесь: https://stackoverflow.com/questions/787 ... except-the
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»