На данный момент у меня есть функция входа в систему. Как только пользователь входит в систему, его данные загружаются на «Главный» экран.
Я пытаюсь реализовать вход с помощью JWT для дополнительной безопасности и узнать, как это сделать, поскольку это хороший способ. практикуюсь в более крупных приложениях, но постоянно сталкиваюсь с ошибкой 401 Unauthorized и не могу ее устранить.
В моем файле appsettings.json есть необходимые параметры для JWT:
Код: Выделить всё
"Jwt": {
"Key": "8D9E3B5F7C2A4E9D1F3C6A7E9B2D4C8F",
"Issuer": "http://localhost:5251",
"Audience": "http://localhost:8080"
}
Код: Выделить всё
// Login method
[HttpPost("login")]
public async Task Login([FromBody] LoginDto loginDto)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.UserName ==
loginDto.UserName);
if (user == null || !BCrypt.Net.BCrypt.Verify(loginDto.Password, user.Password))
{
return Unauthorized(new { message = "Invalid username or password." });
}
// Create the JWT token
var tokenHandler = new JwtSecurityTokenHandler();
var key = _configuration["Jwt:Key"];
if (string.IsNullOrEmpty(key))
{
throw new InvalidOperationException("JWT Key is not configured.");
}
var keyBytes = Encoding.UTF8.GetBytes(key);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(
[
new(ClaimTypes.NameIdentifier, user.Id.ToString()),
new(ClaimTypes.Name, user.UserName),
]),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyBytes), SecurityAlgorithms.HmacSha256Signature),
Issuer = _configuration["Jwt:Issuer"],
Audience = _configuration["Jwt:Audience"]
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
Console.WriteLine("Token: " + tokenString);
Console.WriteLine("Issuer: " + _configuration["Jwt:Issuer"]);
Console.WriteLine("Audience: " + _configuration["Jwt:Audience"]);
return Ok(new { token = tokenString });
}

На вкладке «Сеть» я вижу, что токен находится в запросе, а ответ говорит мне, что он недействителен. [вставьте сюда описание изображения]

Я проверил, что сгенерированный токен на jwt.io верен, и вижу, что «Издатель» и «Аудитория» верны, а также идентификатор пользователя, который я использую для входа в систему. p>
На стороне клиента я собираю токен, сгенерированный на сервере, из ответа и сохраняю его в локальном хранилище для доступа:
Код: Выделить всё
async handleSubmit() {
try {
const url = this.isRegistering
? 'http://localhost:5251/auth/register'
: 'http://localhost:5251/auth/login';
const response = await axios.post(url, {
username : this.username,
password : this.password
});
if (this.isRegistering) {
this.setMessage(response.data.message || "Registration successful! You can now log in.", false);
this.clearFields();
} else {
const token = response.data.token;
if(token) {
localStorage.setItem('token', token)
this.setMessage("Login successful!", false)
this.login({ username: this.username })
this.$router.push({ name: 'Home' });
}
else {
this.setMessage('Login failed. Token not received', true);
}
}
} catch (error) {
this.setMessage(error.response?.data?.message || "An error occurred. Please try again.", true);
console.error('Error:', error.response.data);
}
},
Код: Выделить всё
methods: {
async fetchTasks() {
try {
console.log("token", localStorage.getItem("token"));
const response = await axios.get('http://localhost:5251/api/task/upcoming', {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
this.tasks = response.data;
} catch (error) {
console.error('Error fetching tasks:', error);
}
},
},
Код: Выделить всё
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class TaskController(TaskManagerContext context) : ControllerBase
{
private readonly TaskManagerContext _context = context;
// Method to get the next 3 tasks for a user
[HttpGet("upcoming")]
public async Task GetUpcomingTasks()
{
var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
if (userIdClaim == null)
{
return Unauthorized();
}
var userId = int.Parse(userIdClaim.Value);
// Query tasks for the authenticated user
var upcomingTasks = await _context.Tasks
.Where(t => t.UserId == userId)
.OrderBy(t => t.Date)
.Take(3)
.ToListAsync();
return Ok(upcomingTasks);
}
}
В моем Program.cs службы зарегистрированы в том порядке, в котором они должны быть:< /p>
Код: Выделить всё
using Microsoft.EntityFrameworkCore;
using backend.Data;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using backend.Services;
var builder = WebApplication.CreateBuilder(args);
// Database connection
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext(options =>
options.UseNpgsql(connectionString));
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add controllers support
builder.Services.AddControllersWithViews();
builder.Services.AddCors(options => {
options.AddPolicy("AllowAllOrigins",
builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
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 = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// Apply CORS policy
app.UseCors("AllowAllOrigins");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
app.Run();
Подробнее здесь: https://stackoverflow.com/questions/791 ... pplication