From eb1dc8daa2ce14a141eb2a773a33331bd74ef8dd Mon Sep 17 00:00:00 2001 From: MarcoE Date: Fri, 9 May 2025 14:43:46 +0200 Subject: [PATCH] Aggiunta login --- Template.Maui/MauiProgram.cs | 16 +- Template.Maui/Template.Maui.csproj | 3 +- .../Components/Layout/NavMenu.razor | 2 +- .../Layout/Spinner/SpinnerLayout.razor | 8 + .../Layout/Spinner/SpinnerLayout.razor.css | 43 +++ .../Components/Pages/Calendar.razor | 1 + Template.Shared/Components/Pages/Home.razor | 1 + Template.Shared/Components/Pages/Login.razor | 101 +++++++ .../Components/Pages/Login.razor.css | 61 ++++ .../Components/Pages/PersonalInfo.razor | 1 + Template.Shared/Components/Pages/Users.razor | 1 + Template.Shared/Components/Routes.razor | 52 +++- .../SingleElements/Card/ActivityCard.razor | 18 +- .../Card/ActivityCard.razor.css | 8 +- .../AppAuthenticationStateProvider.cs | 56 ++++ Template.Shared/Template.Shared.csproj | 3 + Template.Shared/_Imports.razor | 6 + Template.Shared/wwwroot/images/log-book.svg | 275 ------------------ .../wwwroot/images/logoIntegry.svg | 70 +++++ .../wwwroot/images/man-doing-squats.svg | 221 -------------- Template.Web/Program.cs | 21 +- Template.Web/Template.Web.csproj | 6 +- 22 files changed, 440 insertions(+), 534 deletions(-) create mode 100644 Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor create mode 100644 Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor.css create mode 100644 Template.Shared/Components/Pages/Login.razor create mode 100644 Template.Shared/Components/Pages/Login.razor.css create mode 100644 Template.Shared/Core/Services/AppAuthenticationStateProvider.cs delete mode 100644 Template.Shared/wwwroot/images/log-book.svg create mode 100644 Template.Shared/wwwroot/images/logoIntegry.svg delete mode 100644 Template.Shared/wwwroot/images/man-doing-squats.svg diff --git a/Template.Maui/MauiProgram.cs b/Template.Maui/MauiProgram.cs index 7941d12..efec070 100644 --- a/Template.Maui/MauiProgram.cs +++ b/Template.Maui/MauiProgram.cs @@ -1,20 +1,17 @@ using IntegryApiClient.MAUI; +using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.Logging; using MudBlazor.Services; using Template.Maui.Services; using Template.Shared; +using Template.Shared.Core.Services; using Template.Shared.Interfaces; namespace Template.Maui { public static class MauiProgram { -#if DEBUG - private const string BaseRestServicesEndpoint = "https://devservices.studioml.it/ems-api/"; - //private const string BaseRestServicesEndpoint = "http://192.168.2.23:8080/ems-api/"; -#else - private const string BaseRestServicesEndpoint = "https://services.studioml.it/ems-api/"; -#endif + private const string AppToken = "f0484398-1f8b-42f5-ab79-5282c164e1d8"; public static MauiApp CreateMauiApp() { @@ -23,7 +20,7 @@ namespace Template.Maui var builder = MauiApp.CreateBuilder(); builder .UseMauiApp() - .UseIntegry(BaseRestServicesEndpoint) + .UseLoginAzienda(AppToken) .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); @@ -32,6 +29,11 @@ namespace Template.Maui builder.Services.AddMauiBlazorWebView(); builder.Services.AddMudServices(); + builder.Services.AddAuthorizationCore(); + builder.Services.AddScoped(); + builder.Services.AddScoped(provider => + provider.GetRequiredService()); + #if DEBUG builder.Services.AddBlazorWebViewDeveloperTools(); builder.Logging.AddDebug(); diff --git a/Template.Maui/Template.Maui.csproj b/Template.Maui/Template.Maui.csproj index e2b0494..585d27a 100644 --- a/Template.Maui/Template.Maui.csproj +++ b/Template.Maui/Template.Maui.csproj @@ -110,8 +110,9 @@ - + + diff --git a/Template.Shared/Components/Layout/NavMenu.razor b/Template.Shared/Components/Layout/NavMenu.razor index dcd4724..9e7e669 100644 --- a/Template.Shared/Components/Layout/NavMenu.razor +++ b/Template.Shared/Components/Layout/NavMenu.razor @@ -39,7 +39,7 @@ protected override Task OnInitializedAsync() { - NavigationManager.LocationChanged += (sender, args) => + NavigationManager.LocationChanged += (_, args) => { var location = args.Location.Remove(0, NavigationManager.BaseUri.Length); diff --git a/Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor b/Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor new file mode 100644 index 0000000..482af43 --- /dev/null +++ b/Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor @@ -0,0 +1,8 @@ +
+ +
+ +@code +{ + [Parameter] public bool FullScreen { get; set; } = true; +} diff --git a/Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor.css b/Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor.css new file mode 100644 index 0000000..5f19126 --- /dev/null +++ b/Template.Shared/Components/Layout/Spinner/SpinnerLayout.razor.css @@ -0,0 +1,43 @@ +.spinner-container { + display: flex; + justify-content: center; + height: calc(100vh - 10.1rem); + align-items: center; + color: var(--mud-palette-primary); +} + +.not-fullScreen { + height: auto !important; + padding: 2rem 0 !important; +} + +.loader { + width: 50px; + aspect-ratio: 1; + border-radius: 50%; + border: 8px solid #0000; + border-right-color: var(--mud-palette-secondary); + position: relative; + animation: l24 1s infinite linear; +} + +.loader:before, +.loader:after { + content: ""; + position: absolute; + inset: -8px; + border-radius: 50%; + border: inherit; + animation: inherit; + animation-duration: 2s; +} + +.loader:after { + animation-duration: 4s; +} + +@keyframes l24 { + 100% { + transform: rotate(1turn) + } +} \ No newline at end of file diff --git a/Template.Shared/Components/Pages/Calendar.razor b/Template.Shared/Components/Pages/Calendar.razor index 1b86d61..4e5c6c4 100644 --- a/Template.Shared/Components/Pages/Calendar.razor +++ b/Template.Shared/Components/Pages/Calendar.razor @@ -1,4 +1,5 @@ @page "/Calendar" +@attribute [Authorize] @using Template.Shared.Components.Layout diff --git a/Template.Shared/Components/Pages/Home.razor b/Template.Shared/Components/Pages/Home.razor index d55c9d7..50f37db 100644 --- a/Template.Shared/Components/Pages/Home.razor +++ b/Template.Shared/Components/Pages/Home.razor @@ -1,4 +1,5 @@ @page "/" +@attribute [Authorize] @code { diff --git a/Template.Shared/Components/Pages/Login.razor b/Template.Shared/Components/Pages/Login.razor new file mode 100644 index 0000000..c432699 --- /dev/null +++ b/Template.Shared/Components/Pages/Login.razor @@ -0,0 +1,101 @@ +@page "/login" +@using Template.Shared.Components.Layout.Spinner +@using Template.Shared.Core.Services +@inject IUserAccountService UserAccountService +@inject AppAuthenticationStateProvider AuthenticationStateProvider + +@if (Spinner) +{ + +} +else +{ +
+
+ +
+ Nome App +
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + @if (_attemptFailed) + { + @ErrorMessage + } +
+
+
+} + +@code { + private SignIn UserData { get; } = new(); + private bool Spinner { get; set; } + private string ErrorMessage { get; set; } = ""; + private bool _attemptFailed; + + protected override void OnInitialized() + { + UserData.CodHash = LocalStorage.GetString("codHash"); + StateHasChanged(); + } + + private async Task SignInUser() + { + _attemptFailed = false; + if (!string.IsNullOrEmpty(UserData.Username) && !string.IsNullOrEmpty(UserData.Password) && !string.IsNullOrEmpty(UserData.CodHash)) + { + Spinner = true; + StateHasChanged(); + + try + { + await UserAccountService.Login(UserData.Username, UserData.Password, UserData.CodHash); + AuthenticationStateProvider.NotifyAuthenticationState(); //Chiamato per forzare il refresh + + LocalStorage.SetString("codHash", UserData.CodHash); + NavigationManager.NavigateTo("/"); + StateHasChanged(); + } + catch (Exception e) + { + Spinner = false; + StateHasChanged(); + + ErrorMessage = e.Message; + _attemptFailed = true; + Console.WriteLine(e); + // Logger<>.LogError(e, e.Message); + } + } + } + + public class SignIn + { + public string? Username { get; set; } + public string? Password { get; set; } + public string? CodHash { get; set; } + } + +} \ No newline at end of file diff --git a/Template.Shared/Components/Pages/Login.razor.css b/Template.Shared/Components/Pages/Login.razor.css new file mode 100644 index 0000000..eeff625 --- /dev/null +++ b/Template.Shared/Components/Pages/Login.razor.css @@ -0,0 +1,61 @@ +.center-box { + margin-top: -1.1rem !important; /* remove page padding */ +} + +.box-area { + width: 930px; +} + +.right-box { + padding: 15px 30px 0 30px; +} + +::placeholder { + font-size: 16px; +} + +.rounded-4 { + border-radius: 20px; +} + +.rounded-5 { + border-radius: 30px; +} + +.bg-white { + background: var(--mud-palette-surface) !important; +} + +.appName { + margin-top: 15px; + font-size: large; + font-weight: 900; + color: var(--mud-palette-primary) +} + +.button-login { + text-align: center; + border: 2px solid var(--mud-palette-primary); + background-color: var(--mud-palette-primary); + border-radius: 25px; + padding: .3rem 2rem; + width: 100%; + font-weight: 700; + color: var(--mud-palette-appbar-text); +} + +.login-footer { + display: flex; + align-items: center; + justify-content: flex-end; +} + +.login-footer span { + font-size: 9px; + color: var(--mud-palette-gray-darker); +} + +.login-footer img { + height: 15px; + margin-left: 4px; +} \ No newline at end of file diff --git a/Template.Shared/Components/Pages/PersonalInfo.razor b/Template.Shared/Components/Pages/PersonalInfo.razor index 79c6876..17cc92d 100644 --- a/Template.Shared/Components/Pages/PersonalInfo.razor +++ b/Template.Shared/Components/Pages/PersonalInfo.razor @@ -1,4 +1,5 @@ @page "/PersonalInfo" +@attribute [Authorize] @using Template.Shared.Components.Layout diff --git a/Template.Shared/Components/Pages/Users.razor b/Template.Shared/Components/Pages/Users.razor index 19b4ebe..a460e24 100644 --- a/Template.Shared/Components/Pages/Users.razor +++ b/Template.Shared/Components/Pages/Users.razor @@ -1,4 +1,5 @@ @page "/Users" +@attribute [Authorize] @using Template.Shared.Components.Layout diff --git a/Template.Shared/Components/Routes.razor b/Template.Shared/Components/Routes.razor index 1709cd1..c732899 100644 --- a/Template.Shared/Components/Routes.razor +++ b/Template.Shared/Components/Routes.razor @@ -1,6 +1,46 @@ - - - - - - +@inject NavigationManager NavigationManager + + + + + + + + +

Authorizing page

+
+ + @if (context.User.Identity?.IsAuthenticated != true) + { + NavigationManager.NavigateTo("/login"); + } + else + { +

You are not authorized to access this resource.

+ } +
+
+ +
+ + Not found + +

Sorry, there's nothing at this address.

+
+
+
+
+
+ + + @* *@ + +
+ +@code { + private ErrorBoundary? ErrorBoundary { get; set; } + // private ExceptionModal ExceptionModal { get; set; } +} \ No newline at end of file diff --git a/Template.Shared/Components/SingleElements/Card/ActivityCard.razor b/Template.Shared/Components/SingleElements/Card/ActivityCard.razor index 8132fd3..32f82f4 100644 --- a/Template.Shared/Components/SingleElements/Card/ActivityCard.razor +++ b/Template.Shared/Components/SingleElements/Card/ActivityCard.razor @@ -1,12 +1,14 @@ -
-
- 14:00 - 1h -
+
+
+
+ 14:00 + 1h +
-
- Format - Preparazione preventivo +
+ Format + Preparazione preventivo +
diff --git a/Template.Shared/Components/SingleElements/Card/ActivityCard.razor.css b/Template.Shared/Components/SingleElements/Card/ActivityCard.razor.css index 99e990e..cee9f50 100644 --- a/Template.Shared/Components/SingleElements/Card/ActivityCard.razor.css +++ b/Template.Shared/Components/SingleElements/Card/ActivityCard.razor.css @@ -1,5 +1,4 @@ .activity-card { - background: var(--mud-palette-background-gray); width: 100%; display: flex; flex-direction: row; @@ -16,6 +15,11 @@ .activity-card.commessa { border-left: 5px solid var(--mud-palette-warning); } +.activity-left-section { + display: flex; + align-items: center; +} + .activity-hours-section { width: min-content; display: flex; @@ -29,7 +33,7 @@ .activity-body-section { width: fit-content; - margin: 0 .5rem; + margin: 0 1rem; display: flex; flex-direction: column; } diff --git a/Template.Shared/Core/Services/AppAuthenticationStateProvider.cs b/Template.Shared/Core/Services/AppAuthenticationStateProvider.cs new file mode 100644 index 0000000..d8bbb91 --- /dev/null +++ b/Template.Shared/Core/Services/AppAuthenticationStateProvider.cs @@ -0,0 +1,56 @@ +using IntegryApiClient.Core.Domain.Abstraction.Contracts.Account; +using System.Security.Claims; +using Microsoft.AspNetCore.Components.Authorization; + +namespace Template.Shared.Core.Services; + +public class AppAuthenticationStateProvider : AuthenticationStateProvider +{ + private readonly IUserSession _userSession; + private readonly IUserAccountService _userAccountService; + + + public AppAuthenticationStateProvider(IUserSession userSession, IUserAccountService userAccountService) + { + _userSession = userSession; + _userAccountService = userAccountService; + + userAccountService.ExpiredUserSession += (_, _) => + NotifyAuthenticationStateChanged(LoadAuthenticationState()); + } + + public override async Task GetAuthenticationStateAsync() + { + return await LoadAuthenticationState(); + } + + public async void SignOut() + { + await _userAccountService.Logout(); + NotifyAuthenticationState(); + } + + public void NotifyAuthenticationState() + { + NotifyAuthenticationStateChanged(LoadAuthenticationState()); + } + + private async Task LoadAuthenticationState() + { + if (!await _userSession.IsLoggedIn() || !await _userSession.IsRefreshTokenValid()) + { + return new AuthenticationState( + new ClaimsPrincipal( + new ClaimsIdentity() + ) + ); + } + + var claimIdentity = new ClaimsIdentity(_userSession.JwtToken!.Claims, "jwt"); + var user = new ClaimsPrincipal(claimIdentity); + + + var authenticationState = new AuthenticationState(user); + return authenticationState; + } +} \ No newline at end of file diff --git a/Template.Shared/Template.Shared.csproj b/Template.Shared/Template.Shared.csproj index 4928d0a..584bf50 100644 --- a/Template.Shared/Template.Shared.csproj +++ b/Template.Shared/Template.Shared.csproj @@ -12,12 +12,15 @@ + + + diff --git a/Template.Shared/_Imports.razor b/Template.Shared/_Imports.razor index 56ee2f9..bd67503 100644 --- a/Template.Shared/_Imports.razor +++ b/Template.Shared/_Imports.razor @@ -1,5 +1,7 @@ @using System.Net.Http @using System.Net.Http.Json +@using IntegryApiClient.Core.Domain.Abstraction.Contracts.Account +@using IntegryApiClient.Core.Domain.Abstraction.Contracts.Storage @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @@ -10,6 +12,10 @@ @using MudBlazor.ThemeManager @using Template.Shared.Core.Helpers @using Template.Shared.Components.SingleElements.Card +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Authorization @using static InteractiveRenderSettings @inject NavigationManager NavigationManager +@inject IUserSession UserSession +@inject ILocalStorage LocalStorage diff --git a/Template.Shared/wwwroot/images/log-book.svg b/Template.Shared/wwwroot/images/log-book.svg deleted file mode 100644 index 2803c6f..0000000 --- a/Template.Shared/wwwroot/images/log-book.svg +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LOG - LOG - - LOG - - - - BOOK - BOOK - - BOOK - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Template.Shared/wwwroot/images/logoIntegry.svg b/Template.Shared/wwwroot/images/logoIntegry.svg new file mode 100644 index 0000000..cf1904f --- /dev/null +++ b/Template.Shared/wwwroot/images/logoIntegry.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Template.Shared/wwwroot/images/man-doing-squats.svg b/Template.Shared/wwwroot/images/man-doing-squats.svg deleted file mode 100644 index c89086b..0000000 --- a/Template.Shared/wwwroot/images/man-doing-squats.svg +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Template.Web/Program.cs b/Template.Web/Program.cs index db0eb37..8bba9af 100644 --- a/Template.Web/Program.cs +++ b/Template.Web/Program.cs @@ -1,28 +1,29 @@ using IntegryApiClient.Blazor; +using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor.Services; using Template.Shared.Components; +using Template.Shared.Core.Services; using Template.Shared.Interfaces; using Template.Web.Services; -#if DEBUG -const string BaseRestServicesEndpoint = "https://devservices.studioml.it/ems-api/"; -//const string BaseRestServicesEndpoint = "http://192.168.2.23:8080/ems-api/"; -#else - const string BaseRestServicesEndpoint = "https://services.studioml.it/ems-api/"; -#endif - var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddMudServices(); builder.Services.AddAuthorizationCore(); -builder.Services.UseIntegry(BaseRestServicesEndpoint); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(provider => provider.GetRequiredService()); + +builder.Services.UseLoginAzienda("f0484398-1f8b-42f5-ab79-5282c164e1d8"); + builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); -builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); -await builder.Build().RunAsync(); +builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + +var host = builder.Build(); +await host.RunAsync(); diff --git a/Template.Web/Template.Web.csproj b/Template.Web/Template.Web.csproj index 067f05e..5d2577e 100644 --- a/Template.Web/Template.Web.csproj +++ b/Template.Web/Template.Web.csproj @@ -8,9 +8,9 @@ - - - + + +