Essaye de l'auth, j'y arrive pas j'en peux plus

issue_auth
Antoine PINAGOT 1 year ago
parent f223bd6a79
commit 343572d22d

@ -1,12 +1,12 @@
<Router AppAssembly="@typeof(App).Assembly"> <Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData"> <Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found> </Found>
<NotFound> <NotFound>
<PageTitle>Not found</PageTitle> <CascadingAuthenticationState>
<LayoutView Layout="@typeof(MainLayout)"> <LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p> <p>Sorry, there's nothing at this address.</p>
</LayoutView> </LayoutView>
</CascadingAuthenticationState>
</NotFound> </NotFound>
</Router> </Router>

@ -7,6 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" /> <PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
<PackageReference Include="Blazorise" Version="1.4.1" /> <PackageReference Include="Blazorise" Version="1.4.1" />
<PackageReference Include="Blazorise.Bootstrap" Version="1.4.0" /> <PackageReference Include="Blazorise.Bootstrap" Version="1.4.0" />

@ -1,4 +1,3 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.8.34330.188 VisualStudioVersion = 17.8.34330.188

@ -0,0 +1,9 @@
namespace HeartTrack.Models.Authentification
{
public class AppUser
{
public string Password { get; set; }
public List<string> Roles { get; set; }
public string UserName { get; set; }
}
}

@ -0,0 +1,9 @@
namespace HeartTrack.Models.Authentification
{
public class CurrentUser
{
public Dictionary<string, string> Claims { get; set; }
public bool IsAuthenticated { get; set; }
public string UserName { get; set; }
}
}

@ -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; }
}
}

@ -1,4 +1,6 @@
@page "/tickets/add" @page "/tickets/add"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "admin")]
@* <AuthorizeView Context="authContext" Roles="admin"> @* <AuthorizeView Context="authContext" Roles="admin">
<Authorized > *@ <Authorized > *@

@ -0,0 +1,28 @@
@page "/login"
@layout AuthLayout
<h1 class="h2 font-weight-normal login-title">
Login
</h1>
<EditForm class="form-signin" OnValidSubmit="OnSubmit" Model="loginRequest">
<DataAnnotationsValidator />
<div class="form-group mb-4 text-center">
<label for="inputUsername">Username</label>
<InputText id="inputUsername" class="form-control max-width-input mx-auto" @bind-Value="loginRequest.UserName" autofocus />
<ValidationMessage For="@(() => loginRequest.UserName)" />
</div>
<div class="form-group mb-4 text-center">
<label for="inputPassword">Password</label>
<InputText type="password" id="inputPassword" class="form-control max-width-input mx-auto" @bind-Value="loginRequest.Password" />
<ValidationMessage For="@(() => loginRequest.Password)" />
</div>
<div class="text-center">
<button class="btn btn-lg btn-success max-width-input" type="submit">SignIn</button>
</div>
<p class="mt-3 text-danger">@errorMessage</p>
</EditForm>

@ -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<Login> Localizer { get; set; }
private string errorMessage { get; set; }
[Inject]
public ILogger<Login> 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}");
}
}
}
}

@ -1,16 +1,38 @@
@page "/" @page "/"
@using System.Globalization @using System.Globalization
<PageTitle>Global View</PageTitle> <AuthorizeView>
<Authorized>
<h1>Hello @context.User.Identity.Name !!</h1>
<h1>Global View</h1> <p>Welcome to Blazor Learner.</p>
This is the global statistics of our website. <ul>
<div style="align-content:flex-start"> @foreach (var claim in context.User.Claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
<PageTitle>Global View</PageTitle>
<h1>Global View</h1>
This is the global statistics of our website.
<div style="align-content:flex-start">
<div style=" display:block; margin:50px;"> <div style=" display:block; margin:50px;">
<p>Number of views of the website</p> <p>Number of views of the website</p>
<MudChart ChartType="ChartType.Line" ChartSeries="@Series" @bind-SelectedIndex="IndexChart" XAxisLabels="@XAxisLabels" Width="100%" Height="350px" ChartOptions="@Options" /> <MudChart ChartType="ChartType.Line" ChartSeries="@Series" @bind-SelectedIndex="IndexChart" XAxisLabels="@XAxisLabels" Width="100%" Height="350px" ChartOptions="@Options" />
</div> </div>
</div> </div>
</Authorized>
<Authorizing>
<h1>Loading ...</h1>
</Authorizing>
<NotAuthorized>
<h1>Authentication Failure!</h1>
<p>You're not signed in.</p>
</NotAuthorized>
</AuthorizeView>

@ -1,5 +1,7 @@
@page "/tickets" @page "/tickets"
@using HeartTrack.Models @using HeartTrack.Models
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "admin")]
<PageTitle>Tickets</PageTitle> <PageTitle>Tickets</PageTitle>

@ -5,6 +5,7 @@ using HeartTrack.Models;
using HeartTrack.Services; using HeartTrack.Services;
using HeartTrack.Services.TicketDataService; using HeartTrack.Services.TicketDataService;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using MudBlazor; using MudBlazor;
using System; using System;
using static MudBlazor.CategoryTypes; using static MudBlazor.CategoryTypes;
@ -31,6 +32,7 @@ namespace HeartTrack.Pages
[Inject] [Inject]
public NavigationManager NavigationManager { get; set; } public NavigationManager NavigationManager { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
// Do not treat this action if is not the first render // Do not treat this action if is not the first render
@ -80,12 +82,12 @@ namespace HeartTrack.Pages
private void OnView(int id) private void OnView(int id)
{ {
NavigationManager.NavigateTo("tickets/view/"+id); NavigationManager.NavigateTo("tickets/view/"+id, true);
} }
private void OnNavigateOnAddClicked() private void OnNavigateOnAddClicked()
{ {
NavigationManager.NavigateTo("tickets/add"); NavigationManager.NavigateTo("tickets/add", true);
} }
private async void OnDelete(Ticket t) private async void OnDelete(Ticket t)

@ -1,6 +1,6 @@
@page "/tickets/view/{Id:int}" @page "/tickets/view/{Id:int}"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "admin")]
<h3>Ticket number @Id</h3> <h3>Ticket number @Id</h3>

@ -10,17 +10,10 @@ using HeartTrack.Services.ActivityDataService;
using HeartTrack.Services.ReportDataService; using HeartTrack.Services.ReportDataService;
using HeartTrack.Services.UserDataService; using HeartTrack.Services.UserDataService;
using HeartTrack.Services.TicketDataService; 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 Microsoft.AspNetCore.Components.Authorization;
using MudBlazor.Services; using MudBlazor.Services;
using HeartTrack.Services.TicketDataServiceFactice; using HeartTrack.Services.TicketDataServiceFactice;
using HeartTrack.Services.AuthentificationService;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -30,6 +23,13 @@ builder.Services.AddMudServices();
// Add services to the container. // Add services to the container.
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor(); builder.Services.AddServerSideBlazor();
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<CustomStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<CustomStateProvider>());
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddHttpClient(); builder.Services.AddHttpClient();
// Add Services // Add Services
@ -115,6 +115,7 @@ if (options?.Value != null)
app.UseRequestLocalization(options.Value); app.UseRequestLocalization(options.Value);
} }
// Add the controller to the endpoint // Add the controller to the endpoint
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {

@ -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<AppUser> users;
[Inject]
private HttpClient Http { get; set; }
[Inject]
private NavigationManager NavigationManager { get; set; }
private readonly ILogger<AuthService> _logger;
public AuthService(IDataService dataService, ILogger<AuthService> logger)
{
users = new List<AppUser>
{
new AppUser { UserName = "Admin", Password = "123456", Roles = new List<string> { "admin" } }
};
_logger = logger;
}
public async Task<CurrentUser> 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<Claim>();
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 !");
}
}
}
}

@ -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<AuthenticationState> 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>("currentUser");
if (currentUser != null && currentUser.IsAuthenticated)
{
// Utilisateur authentifié
}
else
{
currentUser = new CurrentUser();
}
}
}
}

@ -0,0 +1,11 @@
using HeartTrack.Models.Authentification;
namespace HeartTrack.Services.AuthentificationService
{
public interface IAuthService
{
Task<CurrentUser> GetUser(string username, string password);
Task Login(LoginRequest loginRequest);
}
}

@ -1,5 +1,6 @@
using Blazored.LocalStorage; using Blazored.LocalStorage;
using HeartTrack.Models; using HeartTrack.Models;
using HeartTrack.Services.AuthentificationService;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using static MudBlazor.CategoryTypes; using static MudBlazor.CategoryTypes;
@ -11,17 +12,20 @@ namespace HeartTrack.Services
private readonly ILocalStorageService _localStorage; private readonly ILocalStorageService _localStorage;
private readonly NavigationManager _navigationManager; private readonly NavigationManager _navigationManager;
private readonly IWebHostEnvironment _webHostEnvironment; private readonly IWebHostEnvironment _webHostEnvironment;
private readonly CustomStateProvider _customStateProvider;
public DataLocalService( public DataLocalService(
ILocalStorageService localStorage, ILocalStorageService localStorage,
HttpClient http, HttpClient http,
IWebHostEnvironment webHostEnvironment, IWebHostEnvironment webHostEnvironment,
NavigationManager navigationManager) NavigationManager navigationManager,
CustomStateProvider customStateProvider)
{ {
_localStorage = localStorage; _localStorage = localStorage;
_http = http; _http = http;
_webHostEnvironment = webHostEnvironment; _webHostEnvironment = webHostEnvironment;
_navigationManager = navigationManager; _navigationManager = navigationManager;
_customStateProvider = customStateProvider;
} }
public async Task Add(UserModel model) public async Task Add(UserModel model)

@ -1,13 +1,17 @@
using System; using System;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using HeartTrack.Models; using HeartTrack.Models;
using HeartTrack.Services.AuthentificationService;
using HeartTrack.Services.TicketDataService; using HeartTrack.Services.TicketDataService;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
namespace HeartTrack.Services.TicketDataServiceFactice namespace HeartTrack.Services.TicketDataServiceFactice
{ {
public class TicketDataServiceFactice : ITicketDataService public class TicketDataServiceFactice : ITicketDataService
{ {
[CascadingParameter]
private Task<AuthenticationState> AuthenticationState { get; set; }
[Inject] [Inject]
private HttpClient _clientHttp { get; set; } private HttpClient _clientHttp { get; set; }
@ -21,13 +25,14 @@ namespace HeartTrack.Services.TicketDataServiceFactice
private String EmplacementJson { get; set; } 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._clientHttp = clientHttp;
this._localStorage = localStorage; this._localStorage = localStorage;
this._navigationManager = navigationManager; this._navigationManager = navigationManager;
this.EmplacementLocalStorage = "ticketsData"; this.EmplacementLocalStorage = "ticketsData";
this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-tickets.json"; this.EmplacementJson = $"{_navigationManager.BaseUri}data/fake-tickets.json";
this.AuthenticationState = AuthStateProvider.GetAuthenticationStateAsync();
} }
public async Task AddTicket(Ticket t) public async Task AddTicket(Ticket t)

@ -0,0 +1,6 @@
@inherits LayoutComponentBase
<div class="main">
<div class="content px-4">
@Body
</div>
</div>

@ -16,39 +16,16 @@
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" @onclick="ToggleNavMenu"> <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" @onclick="ToggleNavMenu">
<span class="navbat-toggler-icon"></span> <span class="navbat-toggler-icon"></span>
</MudIconButton> </MudIconButton>
<MudSpacer /> <MudSpacer/>
<MudIconButton Icon="@Icons.Material.Filled.ManageAccounts" Color="Color.Inherit" Edge="Edge.End" @onclick="ToggleProfilMenu"/> <CultureSelector></CultureSelector>
<MudMenu Icon="@Icons.Material.Filled.AccountCircle" Color="Color.Inherit" Edge="Edge.End">
<MudMenuItem>Profile</MudMenuItem>
<MudButton type="button" class="btn btn-link ml-md-auto" @onclick="@LogoutClick">Logout</MudButton>
</MudMenu>
</MudAppBar> </MudAppBar>
@* <div class="top-row px-4 auth">
@* <div class="container-fluid toggler-container">
<button title="Navigation menu" class="navbar-toggler custom-toggler" @onclick="ToggleNavMenu">
<span class="navbat-toggler-icon"></span>
</button>
</div> *@
@* Messages, notifs et pp compte à mettre *@
@* <div class="top-row px-4">
<CultureSelector />
<button type="button" class="btn btn-link ml-md-auto" @onclick="@LogoutClick">Logout</button>
</div>
</div> *@
<article class="content px-4"> <article class="content px-4">
@Body @Body
</article> </article>
</main> </main>
</div> </div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
private void ToggleProfilMenu()
{
}
}

@ -1,13 +1,15 @@
using HeartTrack.Services; using HeartTrack.Services;
using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using HeartTrack.Services.AuthentificationService;
namespace HeartTrack.Shared namespace HeartTrack.Shared
{ {
public partial class MainLayout public partial class MainLayout
{ {
/*[Inject]
public CustomStateProvider AuthStateProvider { get; set; }*/ [Inject]
public CustomStateProvider AuthStateProvider { get; set; }
[Inject] [Inject]
public NavigationManager NavigationManager { get; set; } public NavigationManager NavigationManager { get; set; }
@ -15,18 +17,31 @@ namespace HeartTrack.Shared
[CascadingParameter] [CascadingParameter]
private Task<AuthenticationState> AuthenticationState { get; set; } private Task<AuthenticationState> 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) if (!(await AuthenticationState).User.Identity.IsAuthenticated)
{ {
NavigationManager.NavigateTo("/login"); NavigationManager.NavigateTo("/login");
} }
}*/ }
/*private async Task LogoutClick() private async Task LogoutClick()
{ {
await AuthStateProvider.Logout(); await AuthStateProvider.Logout();
NavigationManager.NavigateTo("/login"); NavigationManager.NavigateTo("/login");
}*/ }
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
private void ToggleProfilMenu()
{
}
} }
} }

@ -31,15 +31,15 @@
<span class="oi oi-list-rich" aria-hidden="true"></span> @Localizer["Ban"] <span class="oi oi-list-rich" aria-hidden="true"></span> @Localizer["Ban"]
</NavLink> </NavLink>
</div> </div>
@* </AuthorizeView> @*</AuthorizeView>*@
<AuthorizeView Roles="admin"> *@ <AuthorizeView Roles="admin">
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="tickets"> <NavLink class="nav-link" href="tickets">
<span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Ticket"] <span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Ticket"]
</NavLink> </NavLink>
</div> </div>
@* </AuthorizeView> </AuthorizeView>
<AuthorizeView Roles="owner"> *@ @*@<AuthorizeView Roles="owner"> *@
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link" href="admin"> <NavLink class="nav-link" href="admin">
<span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Admin"] <span class="oi oi-plus" aria-hidden="true"></span> @Localizer["Admin"]

Loading…
Cancel
Save