* Added Authentication
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using FaKrosnoApi.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OrdersManagementDataModel.Dtos;
|
||||
using OrdersManagementDataModel.Services;
|
||||
@@ -28,6 +29,51 @@ public class UsersController(IUserService service) : Controller
|
||||
UserDto? user = await service.GetByUsername(username);
|
||||
return user != null ? Ok(user) : NotFound();
|
||||
}
|
||||
|
||||
[HttpPost("authenticate")]
|
||||
public async Task<IActionResult> Authenticate([FromBody] AuthenticateRequestModel? request)
|
||||
{
|
||||
if (request == null || string.IsNullOrEmpty(request.Login) || string.IsNullOrEmpty(request.Password))
|
||||
{
|
||||
return BadRequest(new { message = "Login i hasło są wymagane" });
|
||||
}
|
||||
|
||||
var user = await service.GetByUsername(request.Login);
|
||||
|
||||
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" });
|
||||
}
|
||||
|
||||
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;
|
||||
user.FailedLoginAttempts = 0;
|
||||
await service.Login(user);
|
||||
|
||||
return Ok(userDto);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<UserDto>> Add([FromBody] UserDto user)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt.Net-Core" Version="1.6.0" />
|
||||
<PackageReference Include="Hangfire" Version="1.8.17" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.11" />
|
||||
|
||||
7
FaKrosnoApi/Models/AuthenticateRequestModel.cs
Normal file
7
FaKrosnoApi/Models/AuthenticateRequestModel.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace FaKrosnoApi.Models;
|
||||
|
||||
public class AuthenticateRequestModel
|
||||
{
|
||||
public string Login { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
@@ -17,16 +18,27 @@
|
||||
</head>
|
||||
|
||||
<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" />
|
||||
<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>
|
||||
<!-- Add chart.js reference if chart components are used in your application. -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.0.1/chart.umd.js" integrity="sha512-gQhCDsnnnUfaRzD8k1L5llCCV6O9HN09zClIzzeJ8OJ9MpGmIlCxm+pdCkqTwqJ4JcjbojFr79rl2F1mzcoLMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<!-- Add chartjs-plugin-datalabels.min.js reference if chart components with data label feature is used in your application. -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" integrity="sha512-JPcRR8yFa8mmCsfrw4TNte1ZvF1e3+1SdGMslZvmrzDYxS69J7J49vkFL8u6u8PlPJK+H3voElBtUCzaXj+6ig==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
|
||||
<script src="_content/Blazor.Bootstrap/blazor.bootstrap.js"></script>
|
||||
<script src="_content/Syncfusion.Blazor.Core/scripts/syncfusion-blazor.min.js" type="text/javascript"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
165
OrdersManagement/Components/Pages/Admin/Users/LoginModule.razor
Normal file
165
OrdersManagement/Components/Pages/Admin/Users/LoginModule.razor
Normal file
@@ -0,0 +1,165 @@
|
||||
@page "/login"
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using OrdersManagement.Models
|
||||
@using Syncfusion.Blazor.Inputs
|
||||
@using Syncfusion.Blazor.Buttons
|
||||
@using Syncfusion.Blazor.Cards
|
||||
@inject UserService UserService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
|
||||
<div class="h-100 d-flex flex-column">
|
||||
<h5>Logowanie</h5>
|
||||
|
||||
@if (!string.IsNullOrEmpty(TempPassword))
|
||||
{
|
||||
<div class="alert alert-info">
|
||||
Twoje tymczasowe hasło to: <strong>@TempPassword</strong>. Użyj go do pierwszego logowania.
|
||||
</div>
|
||||
}
|
||||
|
||||
<SfCard>
|
||||
<CardHeader Title="Zaloguj się"/>
|
||||
<CardContent>
|
||||
<EditForm Model="@LoginModel" FormName="LoginForm" OnValidSubmit="@HandleLogin">
|
||||
<DataAnnotationsValidator/>
|
||||
<ValidationSummary/>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="login">Login</label>
|
||||
<SfTextBox ID="login" @bind-Value="LoginModel.Login" Placeholder="Wprowadź login"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => LoginModel.Login)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Hasło</label>
|
||||
<SfTextBox ID="password" Type="InputType.Password" @bind-Value="LoginModel.Password"
|
||||
Placeholder="Wprowadź hasło" CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => LoginModel.Password)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-3">
|
||||
<SfButton CssClass="e-primary" IsPrimary="true" Type="submit">Zaloguj</SfButton>
|
||||
</div>
|
||||
|
||||
@if (!string.IsNullOrEmpty(ErrorMessage))
|
||||
{
|
||||
<div class="alert alert-danger mt-3">@ErrorMessage</div>
|
||||
}
|
||||
</EditForm>
|
||||
|
||||
@if (ShowChangePassword)
|
||||
{
|
||||
<hr/>
|
||||
<h5>Zmień hasło</h5>
|
||||
<EditForm Model="@ChangePasswordModel" FormName="ChangePasswordForm"
|
||||
OnValidSubmit="@HandleChangePassword">
|
||||
<DataAnnotationsValidator/>
|
||||
<ValidationSummary/>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="newPassword">Nowe hasło</label>
|
||||
<SfTextBox ID="newPassword" Type="InputType.Password"
|
||||
@bind-Value="ChangePasswordModel.NewPassword" Placeholder="Wprowadź nowe hasło"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => ChangePasswordModel.NewPassword)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirmPassword">Potwierdź hasło</label>
|
||||
<SfTextBox ID="confirmPassword" Type="InputType.Password"
|
||||
@bind-Value="ChangePasswordModel.ConfirmPassword" Placeholder="Potwierdź nowe hasło"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => ChangePasswordModel.ConfirmPassword)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-3">
|
||||
<SfButton CssClass="e-success" Type="submit">Zmień hasło</SfButton>
|
||||
</div>
|
||||
</EditForm>
|
||||
}
|
||||
</CardContent>
|
||||
</SfCard>
|
||||
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private LoginModel LoginModel { get; set; } = new();
|
||||
private ChangePasswordModel ChangePasswordModel { get; set; } = new();
|
||||
private bool ShowChangePassword { get; set; }
|
||||
private string TempPassword { get; set; }
|
||||
private string ErrorMessage { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
TempPassword = NavigationManager.Uri.Split('?').Length > 1 ? Uri.UnescapeDataString(NavigationManager.Uri.Split('=')[1]) : null;
|
||||
}
|
||||
|
||||
private async Task HandleLogin()
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Próba logowania dla: {LoginModel.Login}");
|
||||
var user = await UserService.AuthenticateUserAsync(LoginModel.Login, LoginModel.Password);
|
||||
if (user != null)
|
||||
{
|
||||
Console.WriteLine($"Użytkownik {user.Login} znaleziony.");
|
||||
if (user.IsTemporaryPassword)
|
||||
{
|
||||
ShowChangePassword = true;
|
||||
StateHasChanged(); // Wymagane, aby odświeżyć UI
|
||||
}
|
||||
else
|
||||
{
|
||||
await ((CustomAuthenticationStateProvider)AuthenticationStateProvider).MarkUserAsAuthenticated(user);
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage = "Nieprawidłowy login lub hasło";
|
||||
Console.WriteLine(ErrorMessage);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = $"Błąd logowania: {ex.Message}";
|
||||
Console.WriteLine(ErrorMessage);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleChangePassword()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ChangePasswordModel.NewPassword == ChangePasswordModel.ConfirmPassword)
|
||||
{
|
||||
var user = await UserService.GetUserByUsernameAsync(LoginModel.Login);
|
||||
if (user != null)
|
||||
{
|
||||
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(ChangePasswordModel.NewPassword);
|
||||
user.IsTemporaryPassword = false;
|
||||
await UserService.UpdateUserAsync(user);
|
||||
ShowChangePassword = false;
|
||||
LoginModel = new LoginModel();
|
||||
StateHasChanged();
|
||||
NavigationManager.NavigateTo("/login");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorMessage = "Hasła nie są zgodne";
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ErrorMessage = $"Błąd zmiany hasła: {ex.Message}";
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
@page "/register"
|
||||
@using OrdersManagement.Models
|
||||
@using OrdersManagementDataModel.Dtos
|
||||
@using Syncfusion.Blazor.Inputs
|
||||
@using Syncfusion.Blazor.Buttons
|
||||
@using Syncfusion.Blazor.Cards
|
||||
|
||||
@inject UserService UserService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<div class="h-100 d-flex flex-column">
|
||||
<h5>Rejestracja</h5>
|
||||
<br/>
|
||||
<SfCard>
|
||||
<CardHeader Title="Zarejestruj się"/>
|
||||
<CardContent>
|
||||
<EditForm Model="@RegisterModel" OnValidSubmit="HandleRegister">
|
||||
<DataAnnotationsValidator/>
|
||||
<ValidationSummary/>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="login">Login</label>
|
||||
<SfTextBox ID="login" @bind-Value="RegisterModel.Login" Placeholder="Wprowadź login"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => RegisterModel.Login)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<SfTextBox ID="email" @bind-Value="RegisterModel.Email" Placeholder="Wprowadź email"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => RegisterModel.Email)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="firstName">Imię</label>
|
||||
<SfTextBox ID="firstName" @bind-Value="RegisterModel.FirstName" Placeholder="Wprowadź imię"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => RegisterModel.FirstName)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="lastName">Nazwisko</label>
|
||||
<SfTextBox ID="lastName" @bind-Value="RegisterModel.LastName" Placeholder="Wprowadź nazwisko"
|
||||
CssClass="e-outline"/>
|
||||
<ValidationMessage For="@(() => RegisterModel.LastName)"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-3">
|
||||
<SfButton CssClass="e-primary" IsPrimary="true" Type="submit">Zarejestruj</SfButton>
|
||||
</div>
|
||||
</EditForm>
|
||||
</CardContent>
|
||||
</SfCard>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private RegisterModel RegisterModel { get; set; } = new();
|
||||
|
||||
private async Task HandleRegister()
|
||||
{
|
||||
var temporaryPassword = Guid.NewGuid().ToString().Substring(0, 8);
|
||||
var passwordHash = BCrypt.Net.BCrypt.HashPassword(temporaryPassword);
|
||||
|
||||
var user = new UserDto
|
||||
{
|
||||
Login = RegisterModel.Login,
|
||||
PasswordHash = passwordHash,
|
||||
IsTemporaryPassword = true,
|
||||
IsActive = true,
|
||||
ActiveFrom = DateTime.Now,
|
||||
Email = RegisterModel.Email,
|
||||
FirstName = RegisterModel.FirstName,
|
||||
LastName = RegisterModel.LastName,
|
||||
CreatedDate = DateTime.Now,
|
||||
RowPointer = Guid.NewGuid()
|
||||
};
|
||||
|
||||
var result = await UserService.AddUserAsync(user);
|
||||
|
||||
if (result.IsSuccessStatusCode)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/login?tempPassword={Uri.EscapeDataString(temporaryPassword)}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,8 +21,7 @@
|
||||
<GridColumn Field="@nameof(UserDto.IsActive)" HeaderText="Aktywny" Width="80"></GridColumn>
|
||||
<GridColumn Field="@nameof(UserDto.CreatedDate)" HeaderText="Utworzono" Format="d" Width="120"></GridColumn>
|
||||
</GridColumns>
|
||||
<GridEditSettings AllowDeleting="true" ShowDeleteConfirmDialog="true" AllowAdding="true" AllowEditing="true"
|
||||
Mode="EditMode.Normal"></GridEditSettings>
|
||||
<GridEditSettings AllowDeleting="true" ShowDeleteConfirmDialog="true" AllowAdding="true" NewRowPosition="NewRowPosition.Bottom" AllowEditing="true"></GridEditSettings>
|
||||
<GridEvents OnActionBegin="UserActionBegin" OnActionComplete="UserActionComplete" TValue="UserDto"></GridEvents>
|
||||
</SfGrid>§
|
||||
<br/>
|
||||
@@ -169,5 +168,4 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
@page "/EdiCustomerOrders"
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
@inject EdiCustomerOrderService EdiCustomerOrderService
|
||||
@inject NavigationManager NavigationManager
|
||||
@using OrdersManagement.Dtos
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using OrdersManagement.Models
|
||||
@using SytelineSaAppEfDataModel.Dtos
|
||||
@using Syncfusion.Blazor.Grids
|
||||
@using Syncfusion.Blazor.Cards
|
||||
@@ -105,7 +108,7 @@
|
||||
<Content>
|
||||
@if (_responses.Any(x => x.Status == 1))
|
||||
{
|
||||
foreach (ResponseDto 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
|
||||
numerem '@response.ExternalIdentifier'</p>
|
||||
@@ -113,7 +116,7 @@
|
||||
}
|
||||
@if (_responses.Any(x => x.Status == 0))
|
||||
{
|
||||
foreach (ResponseDto 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
|
||||
klienta.<br/>Lista błędów:<br/>@response.Message</p>
|
||||
@@ -135,7 +138,7 @@
|
||||
private IEnumerable<EdiCustomerOrderDto> _ediCustomerOrders = [];
|
||||
private List<EdiCustomerOrderDto> _selectedEdiCustomerOrders = new();
|
||||
|
||||
private List<ResponseDto> _responses = new();
|
||||
private List<ResponseModel> _responses = new();
|
||||
|
||||
private bool _isVisible;
|
||||
private bool? _filter = false;
|
||||
@@ -158,11 +161,11 @@
|
||||
{
|
||||
if (!_selectedEdiCustomerOrders.Any()) return false;
|
||||
|
||||
_responses = new List<ResponseDto>();
|
||||
_responses = new List<ResponseModel>();
|
||||
|
||||
foreach (EdiCustomerOrderDto selectedEdiCustomerOrder in _selectedEdiCustomerOrders)
|
||||
{
|
||||
ResponseDto response = await EdiCustomerOrderService.SendOrderToSyteline(selectedEdiCustomerOrder.RowPointer, selectedEdiCustomerOrder.CustomerOrderNumber);
|
||||
ResponseModel response = await EdiCustomerOrderService.SendOrderToSyteline(selectedEdiCustomerOrder.RowPointer, selectedEdiCustomerOrder.CustomerOrderNumber);
|
||||
|
||||
if (response.Status == 1)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
@page "/"
|
||||
|
||||
@attribute [Authorize]
|
||||
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using OrdersManagement.Components.Pages.Shared
|
||||
@using Syncfusion.Blazor.Grids
|
||||
|
||||
@inject ScheduleOrderService ScheduleOrderService
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="h-100 d-flex flex-column">
|
||||
<h5>Zamówienia DELFOR</h5>
|
||||
|
||||
29
OrdersManagement/CustomAuthenticationStateProvider.cs
Normal file
29
OrdersManagement/CustomAuthenticationStateProvider.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using OrdersManagementDataModel.Dtos;
|
||||
|
||||
namespace OrdersManagement;
|
||||
|
||||
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
|
||||
{
|
||||
private UserDto? _currentUser;
|
||||
|
||||
public override Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||
{
|
||||
var identity = _currentUser != null ? new ClaimsIdentity([new Claim(ClaimTypes.Name, _currentUser.Login)], "CustomAuth") : new ClaimsIdentity();
|
||||
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(identity)));
|
||||
}
|
||||
|
||||
public Task MarkUserAsAuthenticated(UserDto? user)
|
||||
{
|
||||
_currentUser = user;
|
||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void MarkUserAsLoggedOut()
|
||||
{
|
||||
_currentUser = null;
|
||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||
}
|
||||
}
|
||||
14
OrdersManagement/Models/ChangePasswordModel.cs
Normal file
14
OrdersManagement/Models/ChangePasswordModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OrdersManagement.Models;
|
||||
|
||||
public class ChangePasswordModel
|
||||
{
|
||||
[Required(ErrorMessage = "Nowe hasło jest wymagane")]
|
||||
[StringLength(100, MinimumLength = 6, ErrorMessage = "Hasło musi mieć od 6 do 100 znaków")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Potwierdzenie hasła jest wymagane")]
|
||||
[Compare("NewPassword", ErrorMessage = "Hasła muszą się zgadzać")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
12
OrdersManagement/Models/LoginModel.cs
Normal file
12
OrdersManagement/Models/LoginModel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OrdersManagement.Models;
|
||||
|
||||
public class LoginModel
|
||||
{
|
||||
[Required(ErrorMessage = "Login jest wymagany")]
|
||||
public string Login { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Hasło jest wymagane")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
21
OrdersManagement/Models/RegisterModel.cs
Normal file
21
OrdersManagement/Models/RegisterModel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OrdersManagement.Models;
|
||||
|
||||
public class RegisterModel
|
||||
{
|
||||
[Required(ErrorMessage = "Login jest wymagany")]
|
||||
[StringLength(50, ErrorMessage = "Login może mieć maksymalnie 50 znaków")]
|
||||
public string Login { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Email jest wymagany")]
|
||||
[EmailAddress(ErrorMessage = "Nieprawidłowy format email")]
|
||||
[StringLength(100, ErrorMessage = "Email może mieć maksymalnie 100 znaków")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[StringLength(50, ErrorMessage = "Imię może mieć maksymalnie 50 znaków")]
|
||||
public string FirstName { get; set; }
|
||||
|
||||
[StringLength(50, ErrorMessage = "Nazwisko może mieć maksymalnie 50 znaków")]
|
||||
public string LastName { get; set; }
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace OrdersManagement.Dtos
|
||||
namespace OrdersManagement.Models
|
||||
{
|
||||
public class ResponseDto(int status, string identifier, string? message, string? externalIdentifier)
|
||||
public class ResponseModel(int status, string identifier, string? message, string? externalIdentifier)
|
||||
{
|
||||
public int Status { get; set; } = status;
|
||||
public string Identifier { get; set; } = identifier;
|
||||
@@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt.Net-Core" Version="1.6.0" />
|
||||
<PackageReference Include="Blazor.Bootstrap" Version="3.2.0" />
|
||||
<PackageReference Include="Syncfusion.Blazor.Buttons" Version="28.2.3" />
|
||||
<PackageReference Include="Syncfusion.Blazor.Cards" Version="28.2.3" />
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
using Microsoft.AspNetCore.Routing.Constraints;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using OrdersManagement;
|
||||
using OrdersManagement.Components;
|
||||
using OrdersManagement.Services;
|
||||
using Syncfusion.Blazor;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
string faKrosnoApiUrl = builder.Configuration["FaKrosnoApiUrl"] ?? "http://localhost:5001";
|
||||
|
||||
|
||||
builder.Services.AddSyncfusionBlazor();
|
||||
builder.Services.AddBlazorBootstrap();
|
||||
|
||||
string faKrosnoApiUrl = builder.Configuration["FaKrosnoApiUrl"] ?? "http://localhost:5001";
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.LoginPath = "/login";
|
||||
options.LogoutPath = "/login";
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorizationCore();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
|
||||
builder.Services.AddScoped<UserService>();
|
||||
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(faKrosnoApiUrl) });
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
|
||||
|
||||
// Usługi aplikacji
|
||||
builder.Services.AddScoped<ScheduleOrderService>();
|
||||
builder.Services.AddScoped<ScheduleOrderDetailsService>();
|
||||
builder.Services.AddScoped<EdiCustomerOrderService>();
|
||||
builder.Services.AddScoped<CustomerOrderService>();
|
||||
builder.Services.AddScoped<HangfireService>();
|
||||
builder.Services.AddScoped<UserService>();
|
||||
builder.Services.AddScoped<RoleService>();
|
||||
builder.Services.AddScoped<FunctionService>();
|
||||
|
||||
@@ -30,13 +42,17 @@ var app = builder.Build();
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
|
||||
// Włącz autentykację i autoryzację w pipeline
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.MapRazorComponents<App>()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using OrdersManagement.Dtos;
|
||||
using OrdersManagement.Models;
|
||||
using SytelineSaAppEfDataModel.Dtos;
|
||||
|
||||
namespace OrdersManagement.Services
|
||||
@@ -16,14 +16,14 @@ namespace OrdersManagement.Services
|
||||
$"api/EdiCustomerOrders/by-order-number/?customerOrderNumber={customerOrderNumber}");
|
||||
}
|
||||
|
||||
public async Task<ResponseDto> SendOrderToSyteline(Guid customerOrderNumber, string orderNumber)
|
||||
public async Task<ResponseModel> SendOrderToSyteline(Guid customerOrderNumber, string orderNumber)
|
||||
{
|
||||
HttpResponseMessage responseMessage = await httpClient.PostAsync(
|
||||
$"api/EdiCustomerOrders/send-to-syteline?customerOrderNumber={customerOrderNumber}", null);
|
||||
|
||||
if (responseMessage.IsSuccessStatusCode)
|
||||
{
|
||||
return new ResponseDto(1, orderNumber, null, null);
|
||||
return new ResponseModel(1, orderNumber, null, null);
|
||||
}
|
||||
|
||||
string? errorMessage = null;
|
||||
@@ -35,7 +35,7 @@ namespace OrdersManagement.Services
|
||||
errorMessage = string.Join("\r\n", logs.Select(x => x.ErrMsg));
|
||||
}
|
||||
|
||||
return new ResponseDto(0, orderNumber, errorMessage, null);
|
||||
return new ResponseModel(0, orderNumber, errorMessage, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ public class UserService(HttpClient httpClient)
|
||||
{
|
||||
return await httpClient.GetFromJsonAsync<IEnumerable<UserDto>>("api/Users");
|
||||
}
|
||||
|
||||
public async Task<UserDto?> AuthenticateUserAsync(string login, string password)
|
||||
{
|
||||
var response = await httpClient.PostAsJsonAsync("api/users/authenticate", new { Login = login, Password = password });
|
||||
return response.IsSuccessStatusCode ? await response.Content.ReadFromJsonAsync<UserDto>() : null;
|
||||
}
|
||||
|
||||
public async Task<UserDto?> GetUserAsync(Guid userId)
|
||||
{
|
||||
@@ -19,9 +25,9 @@ public class UserService(HttpClient httpClient)
|
||||
return await httpClient.GetFromJsonAsync<UserDto>($"api/Users/by-username/?username={username}");
|
||||
}
|
||||
|
||||
public async Task AddUserAsync(UserDto user)
|
||||
public async Task<HttpResponseMessage> AddUserAsync(UserDto user)
|
||||
{
|
||||
await httpClient.PostAsJsonAsync("api/Users", user);
|
||||
return await httpClient.PostAsJsonAsync("api/Users", user);
|
||||
}
|
||||
|
||||
public async Task UpdateUserAsync(UserDto user)
|
||||
|
||||
@@ -9,6 +9,7 @@ public interface IUserService
|
||||
Task<UserDto?> GetByUsername(string username);
|
||||
Task<int> Add(UserDto userDto);
|
||||
Task<int> Update(UserDto userDto);
|
||||
Task<int> Login(UserDto userDto);
|
||||
Task<int> Delete(Guid id);
|
||||
Task<IList<UserRoleDto>> GetUserRoles(Guid userId);
|
||||
Task<UserDto?> GetUserByLoginAndPassword(string login, string password);
|
||||
|
||||
@@ -56,6 +56,20 @@ public class UserService(OrdersManagementDbContext context, IMapper mapper) : IU
|
||||
context.Users.Update(user);
|
||||
return await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Login(UserDto userDto)
|
||||
{
|
||||
User? user = context.Users.FirstOrDefault(x => x.Id == userDto.Id);
|
||||
|
||||
if (user is null) return 0;
|
||||
|
||||
user.LastLoginDate = DateTime.Now;
|
||||
user.FailedLoginAttempts = 0;
|
||||
|
||||
context.Users.Update(user);
|
||||
|
||||
return await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<int> Delete(Guid id)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user