debut de travail sur l'authentification

blazor
Patrick BRUGIERE 1 year ago
parent 397cca8aab
commit 111a3ecdc0

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

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

@ -0,0 +1,9 @@
namespace adminBlazor.Models
{
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 adminBlazor.Models
{
public class LoginRequest
{
[Required]
public string Password { get; set; }
[Required]
public string UserName { get; set; }
}
}

@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace adminBlazor.Models
{
public class RegisterRequest
{
[Required]
public string Password { get; set; }
[Required]
[Compare(nameof(Password), ErrorMessage = "Passwords do not match!")]
public string PasswordConfirm { get; set; }
[Required]
public string UserName { get; set; }
}
}

@ -0,0 +1,27 @@
@page "/login"
@layout AuthLayout
<h1 class="h2 font-weight-normal login-title">
Login
</h1>
<EditForm class="form-signin" OnValidSubmit="OnSubmit" Model="loginRequest">
<DataAnnotationsValidator />
<label for="inputUsername" class="sr-only">User Name</label>
<InputText id="inputUsername" class="form-control" @bind-Value="loginRequest.UserName" autofocus placeholder="Username" />
<ValidationMessage For="@(() => loginRequest.UserName)" />
<label for="inputPassword" class="sr-only">Password</label>
<InputText type="password" id="inputPassword" class="form-control" placeholder="Password" @bind-Value="loginRequest.Password" />
<ValidationMessage For="@(() => loginRequest.Password)" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<label class="text-danger">@error</label>
<NavLink href="register">
<h6 class="font-weight-normal text-center">Create account</h6>
</NavLink>
</EditForm>

@ -0,0 +1,32 @@
using adminBlazor.Models;
using adminBlazor.Services;
using Microsoft.AspNetCore.Components;
namespace adminBlazor.Pages.Authentication
{
public partial class Login
{
[Inject]
public CustomStateProvider AuthStateProvider { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
private string error { get; set; }
private LoginRequest loginRequest { get; set; } = new LoginRequest();
private async Task OnSubmit()
{
error = null;
try
{
await AuthStateProvider.Login(loginRequest);
NavigationManager.NavigateTo("");
}
catch (Exception ex)
{
error = ex.Message;
}
}
}
}

@ -0,0 +1,29 @@
@page "/register"
@layout AuthLayout
<h1 class="h2 font-weight-normal login-title">
Register
</h1>
<EditForm class="form-signin" OnValidSubmit="OnSubmit" Model="registerRequest">
<DataAnnotationsValidator />
<label for="inputUsername" class="sr-only">User Name</label>
<InputText id="inputUsername" class="form-control" placeholder="Username" autofocus @bind-Value="@registerRequest.UserName" />
<ValidationMessage For="@(() => registerRequest.UserName)" />
<label for="inputPassword" class="sr-only">Password</label>
<InputText type="password" id="inputPassword" class="form-control" placeholder="Password" @bind-Value="@registerRequest.Password" />
<ValidationMessage For="@(() => registerRequest.Password)" />
<label for="inputPasswordConfirm" class="sr-only">Password Confirmation</label>
<InputText type="password" id="inputPasswordConfirm" class="form-control" placeholder="Password Confirmation" @bind-Value="@registerRequest.PasswordConfirm" />
<ValidationMessage For="@(() => registerRequest.PasswordConfirm)" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Create account</button>
<label class="text-danger">@error</label>
<NavLink href="login">
<h6 class="font-weight-normal text-center">Already have an account? Click here to login</h6>
</NavLink>
</EditForm>

@ -0,0 +1,32 @@
using adminBlazor.Models;
using adminBlazor.Services;
using Microsoft.AspNetCore.Components;
namespace adminBlazor.Pages.Authentication
{
public partial class Register
{
[Inject]
public CustomStateProvider AuthStateProvider { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
private string error { get; set; }
private RegisterRequest registerRequest { get; set; } = new RegisterRequest();
private async Task OnSubmit()
{
error = null;
try
{
await AuthStateProvider.Register(registerRequest);
NavigationManager.NavigateTo("");
}
catch (Exception ex)
{
error = ex.Message;
}
}
}
}

@ -24,7 +24,7 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IDataService, DataApiService>(); builder.Services.AddScoped<IDataService, DataApiService>();
//builder.Services.AddScoped<IDataService, DataLocalService>(); builder.Services.AddScoped<IDataService, DataLocalService>();
builder.Services.AddScoped<IVocListService, VocListLocalService>(); builder.Services.AddScoped<IVocListService, VocListLocalService>();

@ -0,0 +1,53 @@
using adminBlazor.Models;
using System.Security.Claims;
namespace adminBlazor.Services
{
public class AuthService : IAuthService
{
private static readonly List<AppUser> CurrentUser;
static AuthService()
{
CurrentUser = new List<AppUser>
{
new AppUser { UserName = "Admin", Password = "123456", Roles = new List<string> { "admin" } }
};
}
public CurrentUser GetUser(string userName)
{
var user = CurrentUser.FirstOrDefault(w => w.UserName == userName);
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 new CurrentUser
{
IsAuthenticated = true,
UserName = user.UserName,
Claims = claims.ToDictionary(c => c.Type, c => c.Value)
};
}
public void Login(LoginRequest loginRequest)
{
var user = CurrentUser.FirstOrDefault(w => w.UserName == loginRequest.UserName && w.Password == loginRequest.Password);
if (user == null)
{
throw new Exception("User name or password invalid !");
}
}
public void Register(RegisterRequest registerRequest)
{
CurrentUser.Add(new AppUser { UserName = registerRequest.UserName, Password = registerRequest.Password, Roles = new List<string> { "guest" } });
}
}
}

@ -0,0 +1,75 @@
using adminBlazor.Models;
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
namespace adminBlazor.Services
{
public class CustomStateProvider : AuthenticationStateProvider
{
private readonly IAuthService _authService;
private CurrentUser _currentUser;
public CustomStateProvider(IAuthService authService)
{
this._authService = authService;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var identity = new ClaimsIdentity();
try
{
var userInfo = GetCurrentUser();
if (userInfo.IsAuthenticated)
{
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");
}
}
catch (HttpRequestException ex)
{
Console.WriteLine("Request failed:" + ex);
}
return new AuthenticationState(new ClaimsPrincipal(identity));
}
public async Task Login(LoginRequest loginParameters)
{
_authService.Login(loginParameters);
// No error - Login the user
var user = _authService.GetUser(loginParameters.UserName);
_currentUser = user;
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
public async Task Logout()
{
_currentUser = null;
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
public async Task Register(RegisterRequest registerParameters)
{
_authService.Register(registerParameters);
// No error - Login the user
var user = _authService.GetUser(registerParameters.UserName);
_currentUser = user;
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
private CurrentUser GetCurrentUser()
{
if (_currentUser != null && _currentUser.IsAuthenticated)
{
return _currentUser;
}
return new CurrentUser();
}
}
}

@ -0,0 +1,137 @@
using adminBlazor.Factories;
using adminBlazor.Models;
using Blazored.LocalStorage;
using Blazorise.Extensions;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
namespace adminBlazor.Services
{
public class DataLocalService : IDataService
{
private readonly HttpClient _http;
private readonly ILocalStorageService _localStorage;
private readonly NavigationManager _navigationManager;
private readonly IWebHostEnvironment _webHostEnvironment;
public DataLocalService(
ILocalStorageService localStorage,
HttpClient http,
IWebHostEnvironment webHostEnvironment,
NavigationManager navigationManager)
{
_localStorage = localStorage;
_webHostEnvironment = webHostEnvironment;
_navigationManager = navigationManager;
_http = http;
}
public async Task Add(UserModel model)
{
var currentData = await _localStorage.GetItemAsync<List<User>>("data");
// Simulate the Id
model.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(UserFactory.Create(model));
// Save the image
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
public async Task<int> Count()
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<User[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<User[]>($"{_navigationManager.BaseUri}fake-data.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<User[]>("data")).Length;
}
public async Task<User> GetById(int id)
{
var currentData = await _localStorage.GetItemAsync<List<User>>("data");
var user = currentData.FirstOrDefault(w => w.Id == id);
if (user == null)
{
throw new Exception($"Unable to found the item with ID: {id}");
}
return user;
}
public async Task<List<User>> List(int currentPage, int pageSize)
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<User[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<User[]>($"{_navigationManager.BaseUri}user.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<User[]>("data")).Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
}
public async Task Update(int id, UserModel model)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<User>>("data");
var user = currentData.FirstOrDefault(w => w.Id == id);
if (user == null)
{
throw new Exception($"Unable to found the item with ID: {id}");
}
// Save the image
//
UserFactory.Update(user, model);
// Modify the content of the item
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
public async Task Delete(int id)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<User>>("data");
// Get the item int the list
var item = currentData.FirstOrDefault(w => w.Id == id);
// Delete item in
currentData.Remove(item);
// Delete the image
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
}
}

@ -0,0 +1,13 @@
using adminBlazor.Models;
namespace adminBlazor.Services
{
public interface IAuthService
{
CurrentUser GetUser(string userName);
void Login(LoginRequest loginRequest);
void Register(RegisterRequest registerRequest);
}
}

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