I know my code is not great but here I am. because I want to improve.
So, it's my first Blazor application. I use Blazor server with Interactive Mode ON in .NET8.I try to implement an authentication system based on cookies like I have found on internet.
Here is the controller class for the login and logout :
public class AuthController(ILogger<AuthController> logger, IHttpContextAccessor? httpContextAccessor, IDataProtectionProvider dataProtectionProvider) : Controller{ [HttpGet("/auth/login")] [AllowAnonymous] public async Task<IActionResult> LogInUser(string name, string password, string returnUrl = "/") { try { IDataProtector protector = dataProtectionProvider.CreateProtector("UserAuth"); string decryptedName = protector.Unprotect(name); string decryptedPassword = protector.Unprotect(password); // Vérifier si un nom d'utilisateur et un mot de passe ont été fournis if (!string.IsNullOrEmpty(decryptedName) && !string.IsNullOrEmpty(decryptedPassword)) { // Recherche d'un utilisateur correspondant dans la base de données using DBInterface dbManager = new(); TUser? dbUser = dbManager.GetAllUsers().FirstOrDefault(u => string.Compare(decryptedName, u.Name, true) == 0); // Vérification du mot de passe if (dbUser != null && Simple3Des.DecryptString(dbUser.PasswordHash) == decryptedPassword) { List<Claim> claims = [ new(ClaimTypes.Name, decryptedName), new(ClaimTypes.Role, dbUser.AccessLevelEnu.ToString()) ]; ClaimsIdentity claimsIdentity = new(claims, CookieAuthenticationDefaults.AuthenticationScheme); AuthenticationProperties authProperties = new() { AllowRefresh = true, IsPersistent = true, }; await httpContextAccessor!.HttpContext!.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties); return Redirect(returnUrl); } } return Redirect("/Login"); } catch (Exception ex) { logger!.LogError("Erreur dans {methodName} : {exceptionType} : {exceptionMessage}", $"{nameof(AuthController)}.{nameof(LogInUser)}", ex.GetType().Name, ex.Message); throw; } } [HttpGet("/auth/logout")] [AllowAnonymous] public async Task<IActionResult> LogOutUser() { await httpContextAccessor!.HttpContext!.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Redirect("/Login"); }}public class UserId{ public string UserName { get; set; } = ""; public string Password { get; set; } = "";}This is called from .razzor component and it works as planned. Except there is Websocket error in the background (Uncaught (in promise) WebSocket is not in the OPEN state). My guess is that this is not "proper" Blazor code since we use websocket and not he proper SignalR stuff or something like that.If the solution is simple I take it but this is not my real problem.
Then, I want something more fancy. I want an autologin based on the client IP. I precise here that this app will be hosted in a intranet server with no access from outside.For that I have implemented my own AuthenticationStateProvider to be able to manage authentication easier.
public class CustomAuthenticationStateProvider(ILogger<CustomAuthenticationStateProvider>? logger, IHttpContextAccessor? httpContextAccessor, NavigationManager? navigationManager) : AuthenticationStateProvider{ public override Task<AuthenticationState> GetAuthenticationStateAsync() { if (httpContextAccessor?.HttpContext?.User.Identity?.IsAuthenticated == true) { return Task.FromResult(new AuthenticationState(httpContextAccessor!.HttpContext!.User)); } else { var usr = GetAutoLogin(); return Task.FromResult(new AuthenticationState(usr)); } } private ClaimsPrincipal GetAutoLogin() { ClaimsPrincipal result = new(); IPAddress? clientIP = httpContextAccessor?.HttpContext?.Connection?.RemoteIpAddress; if (clientIP != null) { byte[] clientIpBytes = clientIP.GetAddressBytes(); if ((clientIpBytes[0] == 192 && clientIpBytes[1] == 168 && clientIpBytes[2] == 8) || clientIP.Equals(IPAddress.Parse("127.0.0.1"))) { try { List<Claim> claims = [ new(ClaimTypes.Name, "Default"), new(ClaimTypes.Role, Kernel.Model.TUser.AccessRights.User.ToString()) ]; ClaimsIdentity claimsIdentity = new(claims, CookieAuthenticationDefaults.AuthenticationScheme); AuthenticationProperties authProperties = new() { AllowRefresh = true, IsPersistent = true }; result = new ClaimsPrincipal(claimsIdentity); } catch (Exception ex) { logger!.LogError("Erreur dans {methodName} : {exceptionType} : {exceptionMessage}", $"{nameof(CustomAuthenticationStateProvider)}.{nameof(GetAutoLogin)}", ex.GetType().Name, ex.Message); throw; } } } return result; }}This works when navigating with buttons on the website, going back or refreshing the page.But if I write an url by and in the navigator, the default user is not taken into account and I am not allowed to view the page...So if I have a <a href="/StockState">Stock</a> it works but if I write the url myself like http://mysite.asd/StockState this is not allowed...
Anybody can help me with that?
I gladly add some more code if requested but I was thinking this is already quite a bit.
I link here my other question because it is related.Authentication in Blazor Server InteractiveThis was about replacing these HttpGet with proper Blazor stuff...