From 343572d22dd753afdfb9cf95b8fc52292b86fb6c Mon Sep 17 00:00:00 2001 From: Antoine PINAGOT Date: Sun, 21 Jan 2024 20:24:00 +0100 Subject: [PATCH] Essaye de l'auth, j'y arrive pas j'en peux plus --- Sources/HeartTrack/App.razor | 14 ++-- Sources/HeartTrack/HeartTrack.csproj | 1 + Sources/HeartTrack/HeartTrack.sln | 1 - .../Models/Authentification/AppUser.cs | 9 +++ .../Models/Authentification/CurrentUser.cs | 9 +++ .../Models/Authentification/LoginRequest.cs | 13 ++++ Sources/HeartTrack/Pages/AddTicket.razor | 2 + .../Pages/Authentification/Login.razor | 28 ++++++++ .../Pages/Authentification/Login.razor.cs | 43 ++++++++++++ Sources/HeartTrack/Pages/Index.razor | 42 +++++++++--- Sources/HeartTrack/Pages/Tickets.razor | 2 + Sources/HeartTrack/Pages/Tickets.razor.cs | 6 +- Sources/HeartTrack/Pages/ViewTicket.razor | 4 +- Sources/HeartTrack/Program.cs | 17 ++--- .../AuthentificationService/AuthService.cs | 61 +++++++++++++++++ .../CustomStateProvider.cs | 65 +++++++++++++++++++ .../AuthentificationService/IAuthService.cs | 11 ++++ .../DataLocalService/DataLocalService.cs | 6 +- .../TicketDataServiceFactice.cs | 7 +- Sources/HeartTrack/Shared/AuthLayout.razor | 6 ++ Sources/HeartTrack/Shared/MainLayout.razor | 39 +++-------- Sources/HeartTrack/Shared/MainLayout.razor.cs | 27 ++++++-- Sources/HeartTrack/Shared/NavMenu.razor | 8 +-- 23 files changed, 348 insertions(+), 73 deletions(-) create mode 100644 Sources/HeartTrack/Models/Authentification/AppUser.cs create mode 100644 Sources/HeartTrack/Models/Authentification/CurrentUser.cs create mode 100644 Sources/HeartTrack/Models/Authentification/LoginRequest.cs create mode 100644 Sources/HeartTrack/Pages/Authentification/Login.razor create mode 100644 Sources/HeartTrack/Pages/Authentification/Login.razor.cs create mode 100644 Sources/HeartTrack/Services/AuthentificationService/AuthService.cs create mode 100644 Sources/HeartTrack/Services/AuthentificationService/CustomStateProvider.cs create mode 100644 Sources/HeartTrack/Services/AuthentificationService/IAuthService.cs create mode 100644 Sources/HeartTrack/Shared/AuthLayout.razor diff --git a/Sources/HeartTrack/App.razor b/Sources/HeartTrack/App.razor index 5212a2b..8a76330 100644 --- a/Sources/HeartTrack/App.razor +++ b/Sources/HeartTrack/App.razor @@ -1,12 +1,12 @@ - + - - + - Not found - -

Sorry, there's nothing at this address.

-
+ + +

Sorry, there's nothing at this address.

+
+
\ No newline at end of file diff --git a/Sources/HeartTrack/HeartTrack.csproj b/Sources/HeartTrack/HeartTrack.csproj index f11256a..d37b4c4 100644 --- a/Sources/HeartTrack/HeartTrack.csproj +++ b/Sources/HeartTrack/HeartTrack.csproj @@ -7,6 +7,7 @@ + diff --git a/Sources/HeartTrack/HeartTrack.sln b/Sources/HeartTrack/HeartTrack.sln index 0cc61e1..c04b1bf 100644 --- a/Sources/HeartTrack/HeartTrack.sln +++ b/Sources/HeartTrack/HeartTrack.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34330.188 diff --git a/Sources/HeartTrack/Models/Authentification/AppUser.cs b/Sources/HeartTrack/Models/Authentification/AppUser.cs new file mode 100644 index 0000000..01bf74e --- /dev/null +++ b/Sources/HeartTrack/Models/Authentification/AppUser.cs @@ -0,0 +1,9 @@ +namespace HeartTrack.Models.Authentification +{ + public class AppUser + { + public string Password { get; set; } + public List Roles { get; set; } + public string UserName { get; set; } + } +} diff --git a/Sources/HeartTrack/Models/Authentification/CurrentUser.cs b/Sources/HeartTrack/Models/Authentification/CurrentUser.cs new file mode 100644 index 0000000..c76fec4 --- /dev/null +++ b/Sources/HeartTrack/Models/Authentification/CurrentUser.cs @@ -0,0 +1,9 @@ +namespace HeartTrack.Models.Authentification +{ + public class CurrentUser + { + public Dictionary Claims { get; set; } + public bool IsAuthenticated { get; set; } + public string UserName { get; set; } + } +} diff --git a/Sources/HeartTrack/Models/Authentification/LoginRequest.cs b/Sources/HeartTrack/Models/Authentification/LoginRequest.cs new file mode 100644 index 0000000..c6c6c2c --- /dev/null +++ b/Sources/HeartTrack/Models/Authentification/LoginRequest.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace HeartTrack.Models.Authentification +{ + public class LoginRequest + { + [Required] + public string Password { get; set; } + + [Required] + public string UserName { get; set; } + } +} diff --git a/Sources/HeartTrack/Pages/AddTicket.razor b/Sources/HeartTrack/Pages/AddTicket.razor index aadec31..5dda534 100644 --- a/Sources/HeartTrack/Pages/AddTicket.razor +++ b/Sources/HeartTrack/Pages/AddTicket.razor @@ -1,4 +1,6 @@ @page "/tickets/add" +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Roles = "admin")] @* *@ diff --git a/Sources/HeartTrack/Pages/Authentification/Login.razor b/Sources/HeartTrack/Pages/Authentification/Login.razor new file mode 100644 index 0000000..20541a1 --- /dev/null +++ b/Sources/HeartTrack/Pages/Authentification/Login.razor @@ -0,0 +1,28 @@ +@page "/login" +@layout AuthLayout + +

+ Login +

+ + \ No newline at end of file diff --git a/Sources/HeartTrack/Pages/Authentification/Login.razor.cs b/Sources/HeartTrack/Pages/Authentification/Login.razor.cs new file mode 100644 index 0000000..5fcdf16 --- /dev/null +++ b/Sources/HeartTrack/Pages/Authentification/Login.razor.cs @@ -0,0 +1,43 @@ +using HeartTrack.Models.Authentification; +using HeartTrack.Services.AuthentificationService; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; + +namespace HeartTrack.Pages.Authentification +{ + public partial class Login + { + [Inject] + public CustomStateProvider AuthStateProvider { get; set; } + + [Inject] + public NavigationManager NavigationManager { get; set; } + + [Inject] + public IStringLocalizer Localizer { get; set; } + + private string errorMessage { get; set; } + + [Inject] + public ILogger Logger { get; set; } + + private LoginRequest loginRequest { get; set; } = new LoginRequest(); + + private async Task OnSubmit() + { + errorMessage = null; + try + { + Logger.LogInformation($"Tentative de connexion pour l'utilisateur : {loginRequest.UserName}"); + await Task.Run(() => AuthStateProvider.Login(loginRequest)); + Logger.LogInformation($"L'utilisateur {loginRequest.UserName} s'est connecté avec succès"); + NavigationManager.NavigateTo(""); + } + catch (Exception ex) + { + errorMessage = ex.Message; + Logger.LogError(ex, $"Échec de connexion pour l'utilisateur : {loginRequest.UserName}"); + } + } + } +} diff --git a/Sources/HeartTrack/Pages/Index.razor b/Sources/HeartTrack/Pages/Index.razor index 6120c47..486cbc6 100644 --- a/Sources/HeartTrack/Pages/Index.razor +++ b/Sources/HeartTrack/Pages/Index.razor @@ -1,16 +1,38 @@ @page "/" @using System.Globalization -Global View + + +

Hello @context.User.Identity.Name !!

-

Global View

+

Welcome to Blazor Learner.

-This is the global statistics of our website. -
-
-

Number of views of the website

- -
+
    + @foreach (var claim in context.User.Claims) + { +
  • @claim.Type: @claim.Value
  • + } +
-
- \ No newline at end of file + Global View + +

Global View

+ + This is the global statistics of our website. +
+
+

Number of views of the website

+ +
+ +
+ +
+ +

Loading ...

+
+ +

Authentication Failure!

+

You're not signed in.

+
+
\ No newline at end of file diff --git a/Sources/HeartTrack/Pages/Tickets.razor b/Sources/HeartTrack/Pages/Tickets.razor index 82a5576..bcab79f 100644 --- a/Sources/HeartTrack/Pages/Tickets.razor +++ b/Sources/HeartTrack/Pages/Tickets.razor @@ -1,5 +1,7 @@ @page "/tickets" @using HeartTrack.Models +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Roles = "admin")] Tickets diff --git a/Sources/HeartTrack/Pages/Tickets.razor.cs b/Sources/HeartTrack/Pages/Tickets.razor.cs index 1e03850..93d1f60 100644 --- a/Sources/HeartTrack/Pages/Tickets.razor.cs +++ b/Sources/HeartTrack/Pages/Tickets.razor.cs @@ -5,6 +5,7 @@ using HeartTrack.Models; using HeartTrack.Services; using HeartTrack.Services.TicketDataService; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Authorization; using MudBlazor; using System; using static MudBlazor.CategoryTypes; @@ -31,6 +32,7 @@ namespace HeartTrack.Pages [Inject] public NavigationManager NavigationManager { get; set; } + protected override async Task OnAfterRenderAsync(bool firstRender) { // Do not treat this action if is not the first render @@ -80,12 +82,12 @@ namespace HeartTrack.Pages private void OnView(int id) { - NavigationManager.NavigateTo("tickets/view/"+id); + NavigationManager.NavigateTo("tickets/view/"+id, true); } private void OnNavigateOnAddClicked() { - NavigationManager.NavigateTo("tickets/add"); + NavigationManager.NavigateTo("tickets/add", true); } private async void OnDelete(Ticket t) diff --git a/Sources/HeartTrack/Pages/ViewTicket.razor b/Sources/HeartTrack/Pages/ViewTicket.razor index 09081ff..f30403b 100644 --- a/Sources/HeartTrack/Pages/ViewTicket.razor +++ b/Sources/HeartTrack/Pages/ViewTicket.razor @@ -1,6 +1,6 @@ @page "/tickets/view/{Id:int}" - - +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Roles = "admin")]

Ticket number @Id

diff --git a/Sources/HeartTrack/Program.cs b/Sources/HeartTrack/Program.cs index 5d6d55a..674781a 100644 --- a/Sources/HeartTrack/Program.cs +++ b/Sources/HeartTrack/Program.cs @@ -10,17 +10,10 @@ using HeartTrack.Services.ActivityDataService; using HeartTrack.Services.ReportDataService; using HeartTrack.Services.UserDataService; using HeartTrack.Services.TicketDataService; -using Blazorise; -using Blazorise.Bootstrap; -using Blazorise.Icons.FontAwesome; -using Microsoft.AspNetCore.Localization; -using System.Globalization; -using Microsoft.Extensions.Options; -using Blazored.LocalStorage; -using HeartTrack.Services; using Microsoft.AspNetCore.Components.Authorization; using MudBlazor.Services; using HeartTrack.Services.TicketDataServiceFactice; +using HeartTrack.Services.AuthentificationService; var builder = WebApplication.CreateBuilder(args); @@ -30,6 +23,13 @@ builder.Services.AddMudServices(); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); + +builder.Services.AddOptions(); +builder.Services.AddAuthorizationCore(); +builder.Services.AddScoped(); +builder.Services.AddScoped(s => s.GetRequiredService()); +builder.Services.AddScoped(); + builder.Services.AddHttpClient(); // Add Services @@ -115,6 +115,7 @@ if (options?.Value != null) app.UseRequestLocalization(options.Value); } + // Add the controller to the endpoint app.UseEndpoints(endpoints => { diff --git a/Sources/HeartTrack/Services/AuthentificationService/AuthService.cs b/Sources/HeartTrack/Services/AuthentificationService/AuthService.cs new file mode 100644 index 0000000..3693533 --- /dev/null +++ b/Sources/HeartTrack/Services/AuthentificationService/AuthService.cs @@ -0,0 +1,61 @@ +using HeartTrack.Models; +using HeartTrack.Models.Authentification; +using Microsoft.AspNetCore.Components; +using System.Security.Claims; + +namespace HeartTrack.Services.AuthentificationService +{ + public class AuthService : IAuthService + { + private readonly List users; + + [Inject] + private HttpClient Http { get; set; } + [Inject] + private NavigationManager NavigationManager { get; set; } + + private readonly ILogger _logger; + + public AuthService(IDataService dataService, ILogger logger) + { + users = new List + { + new AppUser { UserName = "Admin", Password = "123456", Roles = new List { "admin" } } + }; + _logger = logger; + } + + public async Task GetUser(string username, string password) + { + var user = users.FirstOrDefault(w => w.UserName == username && BCrypt.Net.BCrypt.Verify(password, w.Password)); + + if (user == null) + { + throw new Exception("User name or password invalid !"); + } + + var claims = new List(); + claims.AddRange(user.Roles.Select(s => new Claim(ClaimTypes.Role, s))); + + return await Task.FromResult(new CurrentUser + { + IsAuthenticated = true, + UserName = user.UserName, + Claims = claims.ToDictionary(c => c.Type, c => c.Value) + }); + } + + public async Task Login(LoginRequest loginRequest) + { + var user = users.FirstOrDefault(w => w.UserName == loginRequest.UserName && BCrypt.Net.BCrypt.Verify(loginRequest.Password, w.Password)); + + + if (user == null) + { + _logger.LogError($"�chec de connexion pour l'utilisateur : {loginRequest.UserName}"); + throw new Exception("User name or password invalid !"); + } + + } + } +} diff --git a/Sources/HeartTrack/Services/AuthentificationService/CustomStateProvider.cs b/Sources/HeartTrack/Services/AuthentificationService/CustomStateProvider.cs new file mode 100644 index 0000000..57deac9 --- /dev/null +++ b/Sources/HeartTrack/Services/AuthentificationService/CustomStateProvider.cs @@ -0,0 +1,65 @@ +using Blazored.LocalStorage; +using HeartTrack.Models.Authentification; +using Microsoft.AspNetCore.Components.Authorization; +using System.Security.Claims; + +namespace HeartTrack.Services.AuthentificationService +{ + public class CustomStateProvider : AuthenticationStateProvider + { + private readonly IAuthService _authService; + private readonly ILocalStorageService _localStorage; + public CurrentUser? currentUser { get; set; } + + public CustomStateProvider(IAuthService authService, ILocalStorageService localStorage) + { + _authService = authService; + _localStorage = localStorage; + } + + public override async Task GetAuthenticationStateAsync() + { + await RehydrateUserStateAsync(); + var identity = new ClaimsIdentity(); + if (currentUser?.IsAuthenticated == true) + { + var claims = new[] { new Claim(ClaimTypes.Name, currentUser.UserName) } + .Concat(currentUser.Claims.Select(c => new Claim(c.Key, c.Value))); + identity = new ClaimsIdentity(claims, "Server authentication"); + } + + return new AuthenticationState(new ClaimsPrincipal(identity)); + } + + public async Task Login(LoginRequest loginParameters) + { + _authService.Login(loginParameters); + var user = await _authService.GetUser(loginParameters.UserName, loginParameters.Password); + currentUser = user; + + await _localStorage.SetItemAsync("currentUser", currentUser); + + NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); + } + + public async Task Logout() + { + await _localStorage.RemoveItemAsync("currentUser"); + currentUser = null; + NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); + } + + private async Task RehydrateUserStateAsync() + { + currentUser = await _localStorage.GetItemAsync("currentUser"); + if (currentUser != null && currentUser.IsAuthenticated) + { + // Utilisateur authentifié + } + else + { + currentUser = new CurrentUser(); + } + } + } +} diff --git a/Sources/HeartTrack/Services/AuthentificationService/IAuthService.cs b/Sources/HeartTrack/Services/AuthentificationService/IAuthService.cs new file mode 100644 index 0000000..fabf966 --- /dev/null +++ b/Sources/HeartTrack/Services/AuthentificationService/IAuthService.cs @@ -0,0 +1,11 @@ +using HeartTrack.Models.Authentification; + +namespace HeartTrack.Services.AuthentificationService +{ + public interface IAuthService + { + Task GetUser(string username, string password); + + Task Login(LoginRequest loginRequest); + } +} diff --git a/Sources/HeartTrack/Services/DataLocalService/DataLocalService.cs b/Sources/HeartTrack/Services/DataLocalService/DataLocalService.cs index 44eae99..003ed6a 100644 --- a/Sources/HeartTrack/Services/DataLocalService/DataLocalService.cs +++ b/Sources/HeartTrack/Services/DataLocalService/DataLocalService.cs @@ -1,5 +1,6 @@ using Blazored.LocalStorage; using HeartTrack.Models; +using HeartTrack.Services.AuthentificationService; using Microsoft.AspNetCore.Components; using static MudBlazor.CategoryTypes; @@ -11,17 +12,20 @@ namespace HeartTrack.Services private readonly ILocalStorageService _localStorage; private readonly NavigationManager _navigationManager; private readonly IWebHostEnvironment _webHostEnvironment; + private readonly CustomStateProvider _customStateProvider; public DataLocalService( ILocalStorageService localStorage, HttpClient http, IWebHostEnvironment webHostEnvironment, - NavigationManager navigationManager) + NavigationManager navigationManager, + CustomStateProvider customStateProvider) { _localStorage = localStorage; _http = http; _webHostEnvironment = webHostEnvironment; _navigationManager = navigationManager; + _customStateProvider = customStateProvider; } public async Task Add(UserModel model) diff --git a/Sources/HeartTrack/Services/TicketDataService/TicketDataServiceFactice.cs b/Sources/HeartTrack/Services/TicketDataService/TicketDataServiceFactice.cs index 0bda818..0e01f2c 100644 --- a/Sources/HeartTrack/Services/TicketDataService/TicketDataServiceFactice.cs +++ b/Sources/HeartTrack/Services/TicketDataService/TicketDataServiceFactice.cs @@ -1,13 +1,17 @@ using System; using Blazored.LocalStorage; using HeartTrack.Models; +using HeartTrack.Services.AuthentificationService; using HeartTrack.Services.TicketDataService; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Authorization; namespace HeartTrack.Services.TicketDataServiceFactice { public class TicketDataServiceFactice : ITicketDataService { + [CascadingParameter] + private Task AuthenticationState { get; set; } [Inject] private HttpClient _clientHttp { get; set; } @@ -21,13 +25,14 @@ namespace HeartTrack.Services.TicketDataServiceFactice private String EmplacementJson { get; set; } - public TicketDataServiceFactice(HttpClient clientHttp, ILocalStorageService localStorage, NavigationManager navigationManager) + public TicketDataServiceFactice(HttpClient clientHttp, ILocalStorageService localStorage, NavigationManager navigationManager,CustomStateProvider AuthStateProvider) { this._clientHttp = clientHttp; this._localStorage = localStorage; this._navigationManager = navigationManager; this.EmplacementLocalStorage = "ticketsData"; this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-tickets.json"; + this.AuthenticationState = AuthStateProvider.GetAuthenticationStateAsync(); } public async Task AddTicket(Ticket t) diff --git a/Sources/HeartTrack/Shared/AuthLayout.razor b/Sources/HeartTrack/Shared/AuthLayout.razor new file mode 100644 index 0000000..398f38d --- /dev/null +++ b/Sources/HeartTrack/Shared/AuthLayout.razor @@ -0,0 +1,6 @@ +@inherits LayoutComponentBase +
+
+ @Body +
+
diff --git a/Sources/HeartTrack/Shared/MainLayout.razor b/Sources/HeartTrack/Shared/MainLayout.razor index 9896aa6..b34c530 100644 --- a/Sources/HeartTrack/Shared/MainLayout.razor +++ b/Sources/HeartTrack/Shared/MainLayout.razor @@ -16,39 +16,16 @@ - - + + + + Profile + Logout + - @*
- @*
- -
*@ - @* Messages, notifs et pp compte à mettre *@ - @*
- - -
-
*@ - +
@Body
- - -@code { - private bool collapseNavMenu = true; - - private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; - - private void ToggleNavMenu() - { - collapseNavMenu = !collapseNavMenu; - } - private void ToggleProfilMenu() - { - - } -} \ No newline at end of file + \ No newline at end of file diff --git a/Sources/HeartTrack/Shared/MainLayout.razor.cs b/Sources/HeartTrack/Shared/MainLayout.razor.cs index e11af17..4b949c4 100644 --- a/Sources/HeartTrack/Shared/MainLayout.razor.cs +++ b/Sources/HeartTrack/Shared/MainLayout.razor.cs @@ -1,13 +1,15 @@ using HeartTrack.Services; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components; +using HeartTrack.Services.AuthentificationService; namespace HeartTrack.Shared { public partial class MainLayout { - /*[Inject] - public CustomStateProvider AuthStateProvider { get; set; }*/ + + [Inject] + public CustomStateProvider AuthStateProvider { get; set; } [Inject] public NavigationManager NavigationManager { get; set; } @@ -15,18 +17,31 @@ namespace HeartTrack.Shared [CascadingParameter] private Task AuthenticationState { get; set; } - /*protected override async Task OnParametersSetAsync() + private bool collapseNavMenu = true; + + private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; + + protected override async Task OnParametersSetAsync() { if (!(await AuthenticationState).User.Identity.IsAuthenticated) { NavigationManager.NavigateTo("/login"); } - }*/ + } - /*private async Task LogoutClick() + private async Task LogoutClick() { await AuthStateProvider.Logout(); NavigationManager.NavigateTo("/login"); - }*/ + } + + private void ToggleNavMenu() + { + collapseNavMenu = !collapseNavMenu; + } + private void ToggleProfilMenu() + { + + } } } diff --git a/Sources/HeartTrack/Shared/NavMenu.razor b/Sources/HeartTrack/Shared/NavMenu.razor index a007b31..399b2d2 100644 --- a/Sources/HeartTrack/Shared/NavMenu.razor +++ b/Sources/HeartTrack/Shared/NavMenu.razor @@ -31,15 +31,15 @@ @Localizer["Ban"] - @*
- *@ + @**@ + - @* - *@ + + @*@ *@