* Added Authorization which is not working

This commit is contained in:
2025-02-23 21:19:04 +01:00
parent 6774311433
commit 5bcf406465
29 changed files with 407 additions and 210 deletions

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SytelineSaAppEfDataModel.Dtos; using SytelineSaAppEfDataModel.Dtos;
using SytelineSaAppEfDataModel.Services; using SytelineSaAppEfDataModel.Services;

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SytelineSaAppEfDataModel.Dtos; using SytelineSaAppEfDataModel.Dtos;
using SytelineSaAppEfDataModel.Services; using SytelineSaAppEfDataModel.Services;

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SytelineSaAppEfDataModel.Dtos; using SytelineSaAppEfDataModel.Dtos;
using SytelineSaAppEfDataModel.Services; using SytelineSaAppEfDataModel.Services;
@@ -6,6 +7,7 @@ namespace FaKrosnoApi.Controllers
{ {
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
[Authorize]
public class ErrorLogController(IErrorLogService service) : Controller public class ErrorLogController(IErrorLogService service) : Controller
{ {
[HttpGet] [HttpGet]

View File

@@ -1,18 +0,0 @@
using FaKrosnoEfDataModel.Dtos;
using FaKrosnoEfDataModel.Services;
using Microsoft.AspNetCore.Mvc;
namespace FaKrosnoApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class ScheduleOrderDetailsController(IScheduleOrderDetailsService service) : Controller
{
[HttpGet("order/{scheduleOrderId:int}")]
public async Task<ActionResult<IEnumerable<ScheduleOrderDto>>> GetByScheduleOrderId(int scheduleOrderId)
{
IEnumerable<ScheduleOrderDetailDto>? scheduleOrderDetails = await service.GetScheduleOrderDetailsAsync(scheduleOrderId);
return Ok(scheduleOrderDetails);
}
}
}

View File

@@ -1,6 +1,4 @@
using AutoMapper; using FaKrosnoEfDataModel.Dtos;
using FaKrosnoEfDataModel;
using FaKrosnoEfDataModel.Dtos;
using FaKrosnoEfDataModel.Services; using FaKrosnoEfDataModel.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -9,7 +7,6 @@ namespace FaKrosnoApi.Controllers
{ {
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
//[Authorize]
public class ScheduleOrdersController(IScheduleOrderService service) : Controller public class ScheduleOrdersController(IScheduleOrderService service) : Controller
{ {
[HttpGet] [HttpGet]

View File

@@ -1,5 +1,9 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using FaKrosnoApi.Models; using FaKrosnoApi.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using OrdersManagementDataModel.Dtos; using OrdersManagementDataModel.Dtos;
using OrdersManagementDataModel.Services; using OrdersManagementDataModel.Services;
@@ -7,7 +11,7 @@ namespace FaKrosnoApi.Controllers;
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
public class UsersController(IUserService service) : Controller public class UsersController(IUserService service, IConfiguration configuration) : Controller
{ {
[HttpGet] [HttpGet]
public async Task<ActionResult<IEnumerable<UserDto>>> GetAll() public async Task<ActionResult<IEnumerable<UserDto>>> GetAll()
@@ -30,51 +34,41 @@ public class UsersController(IUserService service) : Controller
return user != null ? Ok(user) : NotFound(); return user != null ? Ok(user) : NotFound();
} }
[HttpPost("authenticate")] [HttpPost("login")]
public async Task<IActionResult> Authenticate([FromBody] AuthenticateRequestModel? request) public async Task<IActionResult> Login([FromBody] AuthenticateRequestModel loginDto)
{ {
if (request == null || string.IsNullOrEmpty(request.Login) || string.IsNullOrEmpty(request.Password)) // Sprawdź poprawność użytkownika (np. w bazie danych)
var user = await service.GetByUsername(loginDto.Login);
if(user == null || !BCrypt.Net.BCrypt.Verify(loginDto.Password, user.PasswordHash))
{ {
return BadRequest(new { message = "Login i hasło są wymagane" }); return Unauthorized("Nieprawidłowa nazwa użytkownika lub hasło.");
} }
var user = await service.GetByUsername(request.Login); var claims = new[]
var x = BCrypt.Net.BCrypt.Verify(request.Password, user?.PasswordHash);
if (user == null || !BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash))
{ {
return Unauthorized(new { message = "Nieprawidłowy login lub hasło" }); new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
} new Claim(ClaimTypes.Name, user.Login),
var userDto = new UserDto
{
Id = user.Id,
Login = user.Login,
IsTemporaryPassword = user.IsTemporaryPassword,
IsActive = user.IsActive,
ActiveFrom = user.ActiveFrom,
ActiveTo = user.ActiveTo,
Email = user.Email,
FirstName = user.FirstName,
LastName = user.LastName,
CreatedDate = user.CreatedDate,
LastLoginDate = user.LastLoginDate,
FailedLoginAttempts = user.FailedLoginAttempts,
IsLocked = user.IsLocked,
LockoutEndDate = user.LockoutEndDate,
RowPointer = user.RowPointer
}; };
user.LastLoginDate = DateTime.Now; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]));
user.FailedLoginAttempts = 0; var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
await service.Login(user);
return Ok(userDto); var token = new JwtSecurityToken(
issuer: configuration["Jwt:Issuer"],
audience: configuration["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddHours(1), // Token ważny przez 1 godzinę
signingCredentials: creds);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expires = token.ValidTo
});
} }
[HttpPost] [HttpPost]
public async Task<ActionResult<UserDto>> Add([FromBody] UserDto user) public async Task<ActionResult<UserDto>> Add([FromBody] UserDto user)
{ {

View File

@@ -12,6 +12,8 @@ using OrdersManagementDataModel;
using OrdersManagementDataModel.Services; using OrdersManagementDataModel.Services;
using SytelineSaAppEfDataModel; using SytelineSaAppEfDataModel;
using SytelineSaAppEfDataModel.Services; using SytelineSaAppEfDataModel.Services;
using NSwag;
using NSwag.Generation.Processors.Security;
using FaKrosnoMappingProfile = FaKrosnoEfDataModel.MappingProfile; using FaKrosnoMappingProfile = FaKrosnoEfDataModel.MappingProfile;
using SytelineSaAppMappingProfile = SytelineSaAppEfDataModel.MappingProfile; using SytelineSaAppMappingProfile = SytelineSaAppEfDataModel.MappingProfile;
using OrdersManagementMappingProfile = OrdersManagementDataModel.MappingProfile; using OrdersManagementMappingProfile = OrdersManagementDataModel.MappingProfile;
@@ -30,12 +32,43 @@ builder.Services.Configure<JobSettingsModel>(builder.Configuration.GetSection("J
builder.WebHost.UseUrls("http://*:5001"); builder.WebHost.UseUrls("http://*:5001");
builder.Services.AddAuthentication(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"] ?? string.Empty))
};
});
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddEndpointsApiExplorer();
// Konfiguracja NSwag z obsługą Bearer Token
builder.Services.AddOpenApiDocument(config => builder.Services.AddOpenApiDocument(config =>
{ {
config.Title = "FaKrosnoApi"; config.Title = "FaKrosnoApi";
config.Version = "v1"; config.Version = "v1";
// Dodaj definicję zabezpieczeń Bearer Token
config.AddSecurity("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = OpenApiSecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT",
In = OpenApiSecurityApiKeyLocation.Header,
Description = "Wprowadź token JWT w formacie: Bearer {token}"
});
// Zastosuj zabezpieczenia globalnie
config.OperationProcessors.Add(new OperationSecurityScopeProcessor("Bearer"));
}); });
builder.Services.AddHangfire(config => config builder.Services.AddHangfire(config => config
@@ -52,29 +85,9 @@ builder.Services.AddHangfire(config => config
})); }));
builder.Services.AddHangfireServer(); builder.Services.AddHangfireServer();
// Configure AutoMapper
builder.Services.AddAutoMapper(typeof(FaKrosnoMappingProfile), typeof(SytelineSaAppMappingProfile), builder.Services.AddAutoMapper(typeof(FaKrosnoMappingProfile), typeof(SytelineSaAppMappingProfile),
typeof(OrdersManagementMappingProfile)); typeof(OrdersManagementMappingProfile));
// Configure JWT Authentication
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"]))
};
});
builder.Services.AddScoped<IScheduleOrderService, ScheduleOrderService>(); builder.Services.AddScoped<IScheduleOrderService, ScheduleOrderService>();
builder.Services.AddScoped<IScheduleOrderDetailsService, ScheduleOrderDetailsService>(); builder.Services.AddScoped<IScheduleOrderDetailsService, ScheduleOrderDetailsService>();
builder.Services.AddScoped<IEdiCustomerOrderService, EdiCustomerOrderService>(); builder.Services.AddScoped<IEdiCustomerOrderService, EdiCustomerOrderService>();
@@ -104,11 +117,4 @@ app.MapControllers();
app.UseHangfireDashboard(); app.UseHangfireDashboard();
// var scopeFactory = app.Services.GetRequiredService<IServiceScopeFactory>();
// using (var scope = scopeFactory.CreateScope())
// {
// var scheduledJob = scope.ServiceProvider.GetRequiredService<IScheduleJobService>();
// scheduledJob.Start();
// }
app.Run(); app.Run();

View File

@@ -1,7 +1,7 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
"FaKrosnoConnection": "Server=192.168.0.7;Database=fakrosno;User Id=sa;Password=Tetum#2021!;TrustServerCertificate=true", "FaKrosnoConnection": "Server=192.168.0.7;Database=fakrosnotest;User Id=sa;Password=Tetum#2021!;TrustServerCertificate=true",
"SytelineSaAppConnection": "Server=192.168.0.7;Database=SL_PROD_SA_APP;User Id=sa;Password=Tetum#2021!;TrustServerCertificate=true", "SytelineSaAppConnection": "Server=192.168.0.7;Database=SL_PRODTEST_SA_APP;User Id=sa;Password=Tetum#2021!;TrustServerCertificate=true",
"OrdersManagementConnection": "Server=192.168.0.7;Database=OrdersManagement;User Id=sa;Password=Tetum#2021!;TrustServerCertificate=true" "OrdersManagementConnection": "Server=192.168.0.7;Database=OrdersManagement;User Id=sa;Password=Tetum#2021!;TrustServerCertificate=true"
}, },
"Logging": { "Logging": {
@@ -11,7 +11,7 @@
} }
}, },
"Jwt": { "Jwt": {
"Key": "ThisIsASecretKeyForJwt", "Key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6A7B8C9D0E1F",
"Issuer": "FaKrosnoApi", "Issuer": "FaKrosnoApi",
"Audience": "FaKrosnoClient" "Audience": "FaKrosnoClient"
}, },

View File

@@ -18,19 +18,6 @@
</head> </head>
<body> <body>
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject NavigationManager NavigationManager
@{
var authState = AuthenticationStateProvider.GetAuthenticationStateAsync().Result;
var user = authState.User;
if (!(user.Identity is { IsAuthenticated: true }) && NavigationManager.Uri != NavigationManager.BaseUri + "login")
{
NavigationManager.NavigateTo("/login");
}
}
<Routes @rendermode="@InteractiveServer" /> <Routes @rendermode="@InteractiveServer" />
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

View File

@@ -1,4 +1,9 @@
@page "/login" @page "/login"
@rendermode InteractiveServer
@attribute [AllowAnonymous]
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Authorization
@using OrdersManagement.Models @using OrdersManagement.Models
@using Syncfusion.Blazor.Inputs @using Syncfusion.Blazor.Inputs
@@ -102,18 +107,18 @@
{ {
Console.WriteLine($"Próba logowania dla: {LoginModel.Login}"); Console.WriteLine($"Próba logowania dla: {LoginModel.Login}");
var user = await UserService.AuthenticateUserAsync(LoginModel.Login, LoginModel.Password); var user = await UserService.AuthenticateUserAsync(LoginModel.Login, LoginModel.Password);
if (user != null) if (user != null)
{ {
Console.WriteLine($"Użytkownik {user.Login} znaleziony."); Console.WriteLine($"Użytkownik {user.Login} znaleziony.");
if (user.IsTemporaryPassword) if (user.IsTemporaryPassword)
{ {
ShowChangePassword = true; ShowChangePassword = true;
StateHasChanged(); // Wymagane, aby odświeżyć UI StateHasChanged();
} }
else else
{ {
await ((CustomAuthenticationStateProvider)AuthenticationStateProvider).MarkUserAsAuthenticated(user); NavigationManager.NavigateTo("/ScheduleOrders");
NavigationManager.NavigateTo("/");
} }
} }
else else

View File

@@ -1,5 +1,7 @@
@page "/CustomerOrder/{CustomerOrderId:guid}" @page "/CustomerOrder/{CustomerOrderId:guid}"
@rendermode InteractiveServer
@inject CustomerOrderService CustomerOrderService @inject CustomerOrderService CustomerOrderService
@inject ScheduleOrderService ScheduleOrderService @inject ScheduleOrderService ScheduleOrderService
@using SytelineSaAppEfDataModel.Dtos @using SytelineSaAppEfDataModel.Dtos

View File

@@ -1,4 +1,7 @@
@page "/CustomerOrders" @page "/CustomerOrders"
@rendermode InteractiveServer
@inject CustomerOrderService CustomerOrderService @inject CustomerOrderService CustomerOrderService
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@using SytelineSaAppEfDataModel.Dtos @using SytelineSaAppEfDataModel.Dtos

View File

@@ -1,6 +1,9 @@
@page "/EdiCustomerOrder/{CustomerOrderId:guid}" @page "/EdiCustomerOrder/{CustomerOrderId:guid}"
@rendermode InteractiveServer
@inject EdiCustomerOrderService EdiCustomerOrderService @inject EdiCustomerOrderService EdiCustomerOrderService
@using Microsoft.AspNetCore.Authorization
@using SytelineSaAppEfDataModel.Dtos @using SytelineSaAppEfDataModel.Dtos
@using Syncfusion.Blazor.Grids @using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.Cards @using Syncfusion.Blazor.Cards

View File

@@ -1,6 +1,6 @@
@page "/EdiCustomerOrders" @page "/EdiCustomerOrders"
@attribute [Authorize] @rendermode InteractiveServer
@inject EdiCustomerOrderService EdiCustomerOrderService @inject EdiCustomerOrderService EdiCustomerOrderService
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@@ -108,7 +108,7 @@
<Content> <Content>
@if (_responses.Any(x => x.Status == 1)) @if (_responses.Any(x => x.Status == 1))
{ {
foreach (ResponseModel response in _responses.Where(x => x.Status == 1)) foreach (ResponseModel? response in _responses.Where(x => x.Status == 1))
{ {
<p>Zamówienie EDI @response.Identifier zostało poprawnie zaksięgowane w Zamówieniach klienta pod <p>Zamówienie EDI @response.Identifier zostało poprawnie zaksięgowane w Zamówieniach klienta pod
numerem '@response.ExternalIdentifier'</p> numerem '@response.ExternalIdentifier'</p>
@@ -116,7 +116,7 @@
} }
@if (_responses.Any(x => x.Status == 0)) @if (_responses.Any(x => x.Status == 0))
{ {
foreach (ResponseModel response in _responses.Where(x => x.Status == 0)) foreach (ResponseModel? response in _responses.Where(x => x.Status == 0))
{ {
<p>Błąd: Zamówienie EDI @response.Identifier nie zostało poprawnie zaksięgowane w Zamówieniach <p>Błąd: Zamówienie EDI @response.Identifier nie zostało poprawnie zaksięgowane w Zamówieniach
klienta.<br/>Lista błędów:<br/>@response.Message</p> klienta.<br/>Lista błędów:<br/>@response.Message</p>
@@ -138,7 +138,7 @@
private IEnumerable<EdiCustomerOrderDto> _ediCustomerOrders = []; private IEnumerable<EdiCustomerOrderDto> _ediCustomerOrders = [];
private List<EdiCustomerOrderDto> _selectedEdiCustomerOrders = new(); private List<EdiCustomerOrderDto> _selectedEdiCustomerOrders = new();
private List<ResponseModel> _responses = new(); private List<ResponseModel?> _responses = new();
private bool _isVisible; private bool _isVisible;
private bool? _filter = false; private bool? _filter = false;
@@ -161,11 +161,11 @@
{ {
if (!_selectedEdiCustomerOrders.Any()) return false; if (!_selectedEdiCustomerOrders.Any()) return false;
_responses = new List<ResponseModel>(); _responses = new List<ResponseModel?>();
foreach (EdiCustomerOrderDto selectedEdiCustomerOrder in _selectedEdiCustomerOrders) foreach (EdiCustomerOrderDto selectedEdiCustomerOrder in _selectedEdiCustomerOrders)
{ {
ResponseModel response = await EdiCustomerOrderService.SendOrderToSyteline(selectedEdiCustomerOrder.RowPointer, selectedEdiCustomerOrder.CustomerOrderNumber); ResponseModel? response = await EdiCustomerOrderService.SendOrderToSyteline(selectedEdiCustomerOrder.RowPointer, selectedEdiCustomerOrder.CustomerOrderNumber);
if (response.Status == 1) if (response.Status == 1)
{ {

View File

@@ -0,0 +1,8 @@
@inject NavigationManager Navigation
@code {
protected override void OnInitialized()
{
Navigation.NavigateTo("/login");
}
}

View File

@@ -1,8 +1,10 @@
@page "/ScheduleOrder/{ScheduleOrderId:int}" @page "/ScheduleOrder/{ScheduleOrderId:int}"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Authorization
@using Syncfusion.Blazor.Grids @using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.Lists @using Syncfusion.Blazor.Lists
@inject ScheduleOrderDetailsService ScheduleOrderDetailsService
@inject ScheduleOrderService ScheduleOrderService @inject ScheduleOrderService ScheduleOrderService
<div class="h-100 d-flex flex-column"> <div class="h-100 d-flex flex-column">

View File

@@ -1,14 +1,14 @@
@page "/" @page "/"
@attribute [Authorize]
@inherits LayoutComponentBase
@using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.IdentityModel.Tokens
@using OrdersManagement.Components.Pages.Shared @using OrdersManagement.Components.Pages.Shared
@using Syncfusion.Blazor.Grids @using Syncfusion.Blazor.Grids
@inject ScheduleOrderService ScheduleOrderService @inject ScheduleOrderService ScheduleOrderService
@inject AuthenticationStateProvider AuthStateProvider
@* //@inject AuthTokenHandler TokenHandler *@
<div class="h-100 d-flex flex-column"> <div class="h-100 d-flex flex-column">
<h5>Zamówienia DELFOR</h5> <h5>Zamówienia DELFOR</h5>
@@ -18,17 +18,19 @@
@code { @code {
private IEnumerable<ScheduleOrderDto> _scheduleOrders = []; private IEnumerable<ScheduleOrderDto> _scheduleOrders = [];
protected override async Task OnInitializedAsync() protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
_scheduleOrders = await FetchScheduleOrdersAsync(); if (firstRender)
{
_scheduleOrders = await FetchScheduleOrdersAsync();
StateHasChanged();
}
} }
private async Task<IEnumerable<ScheduleOrderDto>> FetchScheduleOrdersAsync() private async Task<IEnumerable<ScheduleOrderDto>> FetchScheduleOrdersAsync()
{ {
_scheduleOrders = await ScheduleOrderService.GetScheduleOrdersAsync() ?? new List<ScheduleOrderDto>(); _scheduleOrders = await ScheduleOrderService.GetScheduleOrdersAsync() ?? new List<ScheduleOrderDto>();
_scheduleOrders = _scheduleOrders.OrderByDescending(x => x.LastUpdateDate).ToList(); _scheduleOrders = _scheduleOrders.OrderByDescending(x => x.LastUpdateDate).ToList();
StateHasChanged();
return _scheduleOrders; return _scheduleOrders;
} }
@@ -38,5 +40,4 @@
{ {
_gridRef = grid; _gridRef = grid;
} }
} }

View File

@@ -1,29 +1,62 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using OrdersManagementDataModel.Dtos;
namespace OrdersManagement; namespace OrdersManagement;
public class CustomAuthenticationStateProvider : AuthenticationStateProvider public class CustomAuthenticationStateProvider(ILocalStorageService localStorage) : AuthenticationStateProvider
{ {
private UserDto? _currentUser; private string? _token;
private ClaimsPrincipal _currentUser = new(new ClaimsIdentity());
public override Task<AuthenticationState> GetAuthenticationStateAsync() public override Task<AuthenticationState> GetAuthenticationStateAsync()
{ {
var identity = _currentUser != null ? new ClaimsIdentity([new Claim(ClaimTypes.Name, _currentUser.Login)], "CustomAuth") : new ClaimsIdentity(); if (string.IsNullOrEmpty(_token))
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(identity))); {
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
}
var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(_token);
var identity = new ClaimsIdentity(jwtToken.Claims, "jwt");
_currentUser = new ClaimsPrincipal(identity);
return Task.FromResult(new AuthenticationState(_currentUser));
} }
public Task MarkUserAsAuthenticated(UserDto? user) public async Task MarkUserAsAuthenticated(string? token)
{ {
_currentUser = user; _token = token;
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); await localStorage.SetItemAsync("authToken", token);
return Task.CompletedTask; var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(token);
var identity = new ClaimsIdentity(jwtToken.Claims, "jwt");
_currentUser = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(_currentUser)));
} }
public void MarkUserAsLoggedOut() public async Task MarkUserAsLoggedOut()
{ {
_currentUser = null; _token = null;
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); await localStorage.RemoveItemAsync("authToken");
_currentUser = new ClaimsPrincipal(new ClaimsIdentity());
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(_currentUser)));
} }
public async Task InitializeAsync()
{
_token = await localStorage.GetItemAsync<string>("authToken");
if (!string.IsNullOrEmpty(_token))
{
var handler = new JwtSecurityTokenHandler();
var jwtToken = handler.ReadJwtToken(_token);
var identity = new ClaimsIdentity(jwtToken.Claims, "jwt");
_currentUser = new ClaimsPrincipal(identity);
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(_currentUser)));
}
}
public string? GetToken() => _token;
} }

View File

@@ -0,0 +1,7 @@
namespace OrdersManagement.Models;
public class LoginResponseDto
{
public string? Token { get; set; }
public DateTime Expires { get; set; }
}

View File

@@ -9,6 +9,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Core" Version="1.6.0" /> <PackageReference Include="BCrypt.Net-Core" Version="1.6.0" />
<PackageReference Include="Blazor.Bootstrap" Version="3.2.0" /> <PackageReference Include="Blazor.Bootstrap" Version="3.2.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Syncfusion.Blazor.Buttons" Version="28.2.3" /> <PackageReference Include="Syncfusion.Blazor.Buttons" Version="28.2.3" />
<PackageReference Include="Syncfusion.Blazor.Cards" Version="28.2.3" /> <PackageReference Include="Syncfusion.Blazor.Cards" Version="28.2.3" />
<PackageReference Include="Syncfusion.Blazor.Core" Version="28.2.3" /> <PackageReference Include="Syncfusion.Blazor.Core" Version="28.2.3" />

View File

@@ -1,44 +1,58 @@
using Microsoft.AspNetCore.Authentication.Cookies; using Blazored.LocalStorage;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.IdentityModel.Tokens;
using OrdersManagement; using OrdersManagement;
using OrdersManagement.Components; using OrdersManagement.Components;
using OrdersManagement.Services; using OrdersManagement.Services;
using Syncfusion.Blazor; using Syncfusion.Blazor;
using System.Text;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
string faKrosnoApiUrl = builder.Configuration["FaKrosnoApiUrl"] ?? "http://localhost:5001"; string faKrosnoApiUrl = builder.Configuration["FaKrosnoApiUrl"] ?? "http://localhost:5001";
builder.Services.AddSyncfusionBlazor(); builder.Services.AddSyncfusionBlazor();
builder.Services.AddBlazorBootstrap(); builder.Services.AddBlazorBootstrap();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(options => .AddJwtBearer(options =>
{ {
options.LoginPath = "/login"; options.TokenValidationParameters = new TokenValidationParameters
options.LogoutPath = "/login"; {
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"]))
};
}); });
builder.Services.AddAuthorizationCore(); builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>(); builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
builder.Services.AddScoped<UserService>();
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(faKrosnoApiUrl) });
builder.Services.AddRazorComponents().AddInteractiveServerComponents(); builder.Services.AddHttpClient("FaKrosnoApi", client =>
{
client.BaseAddress = new Uri(faKrosnoApiUrl);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
});
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
// Usługi aplikacji
builder.Services.AddScoped<ScheduleOrderService>(); builder.Services.AddScoped<ScheduleOrderService>();
builder.Services.AddScoped<ScheduleOrderDetailsService>();
builder.Services.AddScoped<EdiCustomerOrderService>(); builder.Services.AddScoped<EdiCustomerOrderService>();
builder.Services.AddScoped<CustomerOrderService>(); builder.Services.AddScoped<CustomerOrderService>();
builder.Services.AddScoped<HangfireService>(); builder.Services.AddScoped<HangfireService>();
builder.Services.AddScoped<RoleService>(); builder.Services.AddScoped<RoleService>();
builder.Services.AddScoped<FunctionService>(); builder.Services.AddScoped<FunctionService>();
builder.Services.AddScoped<UserService>();
builder.Services.AddScoped<ErrorLogService>();
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment()) if (!app.Environment.IsDevelopment())
{ {
app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseExceptionHandler("/Error", createScopeForErrors: true);
@@ -49,7 +63,6 @@ app.UseHttpsRedirection();
app.UseStaticFiles(); app.UseStaticFiles();
app.UseRouting(); app.UseRouting();
// Włącz autentykację i autoryzację w pipeline
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();

View File

@@ -1,17 +1,36 @@
using Microsoft.AspNetCore.Components.Authorization;
using SytelineSaAppEfDataModel.Dtos; using SytelineSaAppEfDataModel.Dtos;
namespace OrdersManagement.Services; namespace OrdersManagement.Services;
public class CustomerOrderService(HttpClient httpClient) public class CustomerOrderService(
IHttpClientFactory httpClientFactory,
AuthenticationStateProvider authenticationStateProvider)
: ServiceBase<CustomerOrderDto>(httpClientFactory, authenticationStateProvider)
{ {
public async Task<IEnumerable<CustomerOrderDto>?> GetCustomerOrdersAsync() public async Task<IEnumerable<CustomerOrderDto>?> GetCustomerOrdersAsync()
{ {
return await httpClient.GetFromJsonAsync<IEnumerable<CustomerOrderDto>>("api/CustomerOrders"); try
{
return await GetListAsync("api/CustomerOrders");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Błąd HTTP w GetCustomerOrdersAsync: {ex.Message}");
return null;
}
} }
public async Task<CustomerOrderDto?> GetCustomerOrderAsync(Guid customerOrderNumber) public async Task<CustomerOrderDto?> GetCustomerOrderAsync(Guid customerOrderNumber)
{ {
return await httpClient.GetFromJsonAsync<CustomerOrderDto>( try
$"api/CustomerOrders/by-order-number/?customerOrderNumber={customerOrderNumber}"); {
return await GetByIdAsync($"api/CustomerOrders/by-order-number/?customerOrderNumber={customerOrderNumber}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Błąd HTTP w GetScheduleOrderAsync: {ex.Message}");
return null;
}
} }
} }

View File

@@ -1,41 +1,63 @@
using OrdersManagement.Models; using Microsoft.AspNetCore.Components.Authorization;
using OrdersManagement.Models;
using SytelineSaAppEfDataModel.Dtos; using SytelineSaAppEfDataModel.Dtos;
namespace OrdersManagement.Services namespace OrdersManagement.Services
{ {
public class EdiCustomerOrderService(HttpClient httpClient) public class EdiCustomerOrderService(IHttpClientFactory httpClientFactory, AuthenticationStateProvider authenticationStateProvider, ErrorLogService errorLogService) : ServiceBase<EdiCustomerOrderDto>(httpClientFactory, authenticationStateProvider)
{ {
public async Task<IEnumerable<EdiCustomerOrderDto>?> GetEdiCustomerOrdersAsync() public async Task<IEnumerable<EdiCustomerOrderDto>?> GetEdiCustomerOrdersAsync()
{ {
return await httpClient.GetFromJsonAsync<IEnumerable<EdiCustomerOrderDto>>("api/EdiCustomerOrders"); try
{
return await GetListAsync("api/EdiCustomerOrders");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Błąd HTTP w GetEdiCustomerOrdersAsync: {ex.Message}");
return null;
}
} }
public async Task<EdiCustomerOrderDto?> GetEdiCustomerOrderAsync(Guid customerOrderNumber) public async Task<EdiCustomerOrderDto?> GetEdiCustomerOrderAsync(Guid customerOrderNumber)
{ {
return await httpClient.GetFromJsonAsync<EdiCustomerOrderDto>( try
$"api/EdiCustomerOrders/by-order-number/?customerOrderNumber={customerOrderNumber}"); {
return await GetByIdAsync($"api/EdiCustomerOrders/by-order-number/?customerOrderNumber={customerOrderNumber}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Błąd HTTP w GetEdiCustomerOrdersAsync: {ex.Message}");
return null;
}
} }
public async Task<ResponseModel> SendOrderToSyteline(Guid customerOrderNumber, string orderNumber) public async Task<ResponseModel?> SendOrderToSyteline(Guid customerOrderNumber, string orderNumber)
{ {
HttpResponseMessage responseMessage = await httpClient.PostAsync( try
$"api/EdiCustomerOrders/send-to-syteline?customerOrderNumber={customerOrderNumber}", null);
if (responseMessage.IsSuccessStatusCode)
{ {
return new ResponseModel(1, orderNumber, null, null); HttpResponseMessage responseMessage = await PostAsync($"api/EdiCustomerOrders/send-to-syteline?customerOrderNumber={customerOrderNumber}");
if (responseMessage.IsSuccessStatusCode)
{
return new ResponseModel(1, orderNumber, null, null);
}
string? errorMessage = null;
IEnumerable<ErrorLogDto>? logs = await errorLogService.GetErrorLogsAsync(customerOrderNumber);
if (logs != null)
{
errorMessage = string.Join("\r\n", logs.Select(x => x.ErrMsg));
}
return new ResponseModel(0, orderNumber, errorMessage, null);
} }
catch (HttpRequestException ex)
string? errorMessage = null;
IEnumerable<ErrorLogDto>? logs = await httpClient.GetFromJsonAsync<IEnumerable<ErrorLogDto>>(
$"api/ErrorLog/by-order-number/?customerOrderNumber={customerOrderNumber}");
if (logs != null)
{ {
errorMessage = string.Join("\r\n", logs.Select(x => x.ErrMsg)); Console.WriteLine($"Błąd HTTP w GetEdiCustomerOrdersAsync: {ex.Message}");
return null;
} }
return new ResponseModel(0, orderNumber, errorMessage, null);
} }
} }
} }

View File

@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Components.Authorization;
using SytelineSaAppEfDataModel.Dtos;
namespace OrdersManagement.Services;
public class ErrorLogService(
IHttpClientFactory httpClientFactory,
AuthenticationStateProvider authenticationStateProvider)
: ServiceBase<ErrorLogDto>(httpClientFactory, authenticationStateProvider)
{
public async Task<IEnumerable<ErrorLogDto>?> GetErrorLogsAsync(Guid customerOrderNumber)
{
try
{
return await GetListAsync($"api/CustomerOrders/by-order-number/?customerOrderNumber={customerOrderNumber}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Błąd HTTP w GetCustomerOrdersAsync: {ex.Message}");
return null;
}
}
}

View File

@@ -1,13 +0,0 @@
using FaKrosnoEfDataModel.Dtos;
namespace OrdersManagement.Services
{
public class ScheduleOrderDetailsService(HttpClient httpClient)
{
public async Task<IEnumerable<ScheduleOrderDetailDto>?> GetScheduleOrderDetails(int scheduleOrderId)
{
return await httpClient.GetFromJsonAsync<IEnumerable<ScheduleOrderDetailDto>>(
$"api/scheduleOrderDetails/order/{scheduleOrderId}");
}
}
}

View File

@@ -1,18 +1,38 @@
using FaKrosnoEfDataModel.Dtos; using System.Net.Http.Headers;
using Blazored.LocalStorage;
using FaKrosnoEfDataModel.Dtos;
using Microsoft.AspNetCore.Components.Authorization;
namespace OrdersManagement.Services namespace OrdersManagement.Services;
public class ScheduleOrderService(
IHttpClientFactory httpClientFactory,
AuthenticationStateProvider authenticationStateProvider)
: ServiceBase<ScheduleOrderDto>(httpClientFactory, authenticationStateProvider)
{ {
public class ScheduleOrderService(HttpClient httpClient) public async Task<IEnumerable<ScheduleOrderDto>?> GetScheduleOrdersAsync()
{ {
public async Task<IEnumerable<ScheduleOrderDto>?> GetScheduleOrdersAsync() try
{ {
return await httpClient.GetFromJsonAsync<IEnumerable<ScheduleOrderDto>>("api/ScheduleOrders"); return await GetListAsync("api/ScheduleOrders");
} }
catch (HttpRequestException ex)
public async Task<ScheduleOrderDto?> GetScheduleOrderAsync(int scheduleOrderId)
{ {
return await httpClient.GetFromJsonAsync<ScheduleOrderDto>( Console.WriteLine($"Błąd HTTP w GetScheduleOrdersAsync: {ex.Message}");
$"api/ScheduleOrders/{scheduleOrderId}"); return null;
}
}
public async Task<ScheduleOrderDto?> GetScheduleOrderAsync(int scheduleOrderId)
{
try
{
return await GetByIdAsync($"api/ScheduleOrders/{scheduleOrderId}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Błąd HTTP w GetScheduleOrderAsync: {ex.Message}");
return null;
} }
} }
} }

View File

@@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Components.Authorization;
namespace OrdersManagement.Services;
public class ServiceBase<T> where T : class
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
private readonly HttpClient _httpClient;
protected ServiceBase(IHttpClientFactory httpClientFactory, AuthenticationStateProvider authenticationStateProvider)
{
_authenticationStateProvider = authenticationStateProvider;
_httpClient = httpClientFactory.CreateClient("FaKrosnoApi");
_ = Configure();
}
protected async Task<IEnumerable<T>?> GetListAsync(string request)
{
var response = await _httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<IEnumerable<T>>();
}
protected async Task<T?> GetByIdAsync(string request)
{
var response = await _httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>();
}
protected async Task<HttpResponseMessage> PostAsync(string request)
{
var response = await _httpClient.PostAsync(request, null);
response.EnsureSuccessStatusCode();
return response;
}
private async Task Configure()
{
var token = await GetToken();
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
}
private async Task<string?> GetToken()
{
await ((CustomAuthenticationStateProvider)_authenticationStateProvider).InitializeAsync();
return ((CustomAuthenticationStateProvider)_authenticationStateProvider).GetToken();
}
}

View File

@@ -1,42 +1,62 @@
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization;
using OrdersManagement.Models;
using OrdersManagementDataModel.Dtos; using OrdersManagementDataModel.Dtos;
namespace OrdersManagement.Services; namespace OrdersManagement.Services;
public class UserService(HttpClient httpClient) public class UserService(IHttpClientFactory clientFactory, AuthenticationStateProvider authStateProvider)
{ {
private readonly HttpClient _httpClient = clientFactory.CreateClient("FaKrosnoApi");
public async Task<IEnumerable<UserDto>?> GetUsersAsync() public async Task<IEnumerable<UserDto>?> GetUsersAsync()
{ {
return await httpClient.GetFromJsonAsync<IEnumerable<UserDto>>("api/Users"); return await _httpClient.GetFromJsonAsync<IEnumerable<UserDto>>("api/Users");
} }
public async Task<UserDto?> AuthenticateUserAsync(string login, string password) public async Task<UserDto?> AuthenticateUserAsync(string login, string password)
{ {
var response = await httpClient.PostAsJsonAsync("api/users/authenticate", new { Login = login, Password = password }); try
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<UserDto>() : null; {
var response = await _httpClient.PostAsJsonAsync("api/Users/login", new { Login = login, Password = password });
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<LoginResponseDto>();
if (result?.Token == null) return null;
await ((CustomAuthenticationStateProvider)authStateProvider).MarkUserAsAuthenticated(result.Token);
return await GetUserByUsernameAsync(login);
}
catch (Exception ex)
{
Console.WriteLine($"Błąd logowania: {ex.Message}");
return null;
}
} }
public async Task<UserDto?> GetUserAsync(Guid userId) public async Task<UserDto?> GetUserAsync(Guid userId)
{ {
return await httpClient.GetFromJsonAsync<UserDto>($"api/Users/by-id/?id={userId}"); return await _httpClient.GetFromJsonAsync<UserDto>($"api/Users/by-id/?id={userId}");
} }
public async Task<UserDto?> GetUserByUsernameAsync(string username) public async Task<UserDto?> GetUserByUsernameAsync(string username)
{ {
return await httpClient.GetFromJsonAsync<UserDto>($"api/Users/by-username/?username={username}"); return await _httpClient.GetFromJsonAsync<UserDto>($"api/Users/by-username/?username={username}");
} }
public async Task<HttpResponseMessage> AddUserAsync(UserDto user) public async Task<HttpResponseMessage> AddUserAsync(UserDto user)
{ {
return await httpClient.PostAsJsonAsync("api/Users", user); return await _httpClient.PostAsJsonAsync("api/Users", user);
} }
public async Task UpdateUserAsync(UserDto user) public async Task UpdateUserAsync(UserDto user)
{ {
await httpClient.PutAsJsonAsync("api/Users", user); await _httpClient.PutAsJsonAsync("api/Users", user);
} }
public async Task DeleteUserAsync(Guid userId) public async Task DeleteUserAsync(Guid userId)
{ {
await httpClient.DeleteAsync($"api/Users/?id={userId}"); await _httpClient.DeleteAsync($"api/Users/?id={userId}");
} }
} }

View File

@@ -5,5 +5,10 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"Jwt": {
"Key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6A7B8C9D0E1F",
"Issuer": "FaKrosnoApi",
"Audience": "FaKrosnoClient"
},
"AllowedHosts": "*" "AllowedHosts": "*"
} }