diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/App.razor b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/App.razor
index f1f9f4c..3537306 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/App.razor
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/App.razor
@@ -15,7 +15,7 @@
-
+
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/MainLayout.razor b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/MainLayout.razor
index 5939f45..f126709 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/MainLayout.razor
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/MainLayout.razor
@@ -28,7 +28,7 @@
-
+
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/NavMenu.razor b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/NavMenu.razor
index 1dde764..0815038 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/NavMenu.razor
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Layout/NavMenu.razor
@@ -6,18 +6,18 @@
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Login.razor b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Login.razor
index 937be53..e9283fd 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Login.razor
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Login.razor
@@ -2,10 +2,14 @@
@using FluentBlazorAuth.Data
@using FluentBlazorAuth.Models.ViewModels
@using System.Security.Claims
+@using FluentBlazorAuth.Services
+@using FluentBlazorAuth.States
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authentication.Cookies
-@inject AppDbContext AppDbContext
+@inject AuthenticationStateProvider AuthenticationStateProvider
+@inject IUserAccountService UserAccountService
@inject NavigationManager NavManager
+@rendermode RenderMode.InteractiveServer
@@ -40,9 +44,6 @@
@code {
- [CascadingParameter]
- public HttpContext? HttpContext { get; set; }
-
[SupplyParameterFromForm]
public LoginViewModel LoginViewModel { get; set; }
@@ -56,24 +57,15 @@
async Task OnLoginSubmit(EditContext context)
{
- var userAccount = AppDbContext.UserAccounts.Where(u => u.UserName == LoginViewModel.UserName).FirstOrDefault();
- if (userAccount is null || userAccount.Password != LoginViewModel.Password)
+ var authProvider = (CustomAuthenticationStateProvider)AuthenticationStateProvider;
+ var userAccount = UserAccountService.Authenticate(LoginViewModel.UserName, LoginViewModel.Password);
+ if (userAccount == null)
{
- errorMessage = "Please login again.";
- await InvokeAsync(StateHasChanged);
+ errorMessage = "Invalid User account.";
return;
}
- var claims = new List
- {
- new Claim(ClaimTypes.Name, LoginViewModel.UserName),
- new Claim(ClaimTypes.Role, userAccount.Role)
- };
-
- var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
- var principal = new ClaimsPrincipal(identity);
- await HttpContext.SignInAsync(principal);
-
+ authProvider.MarkUserAsAuthenticated(userAccount);
NavManager.NavigateTo("/");
}
}
\ No newline at end of file
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Logout.razor b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Logout.razor
index be72528..996982e 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Logout.razor
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Components/Pages/Account/Logout.razor
@@ -1,6 +1,7 @@
@page "/logout"
+@using FluentBlazorAuth.States
@using Microsoft.AspNetCore.Authentication
-@inject NavigationManager NavManager
+@inject AuthenticationStateProvider AuthenticationStateProvider
@rendermode InteractiveServer
@@ -17,10 +18,9 @@
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
- if (HttpContext.User.Identity.IsAuthenticated)
- await HttpContext.SignOutAsync();
- NavManager.NavigateTo("/logout", true);
+ var authProvider = (CustomAuthenticationStateProvider)AuthenticationStateProvider;
+ authProvider.MarkUserAsLoggedOut();
}
}
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth.csproj b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth.csproj
index 8d8c85f..b015a6c 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth.csproj
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth.csproj
@@ -7,7 +7,6 @@
-
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Program.cs b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Program.cs
index 60ff998..60a9753 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Program.cs
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Program.cs
@@ -3,7 +3,9 @@ using FluentBlazorAuth.Components;
using Microsoft.AspNetCore.Authentication.Cookies;
using FluentBlazorAuth.Data;
using Microsoft.EntityFrameworkCore;
-using Blazored.LocalStorage;
+using FluentBlazorAuth.Services;
+using FluentBlazorAuth.States;
+using Microsoft.AspNetCore.Components.Authorization;
namespace FluentBlazorAuth;
@@ -31,8 +33,10 @@ public class Program
builder.Services.AddCascadingAuthenticationState();
#endregion
- #region LocalStorage
- builder.Services.AddBlazoredLocalStorage();
+ #region AuthTest
+ builder.Services.AddScoped();
+ builder.Services.AddScoped();
+ builder.Services.AddHttpContextAccessor();
#endregion
#region Database
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Services/IUserAccountService.cs b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Services/IUserAccountService.cs
new file mode 100644
index 0000000..700051d
--- /dev/null
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Services/IUserAccountService.cs
@@ -0,0 +1,9 @@
+using FluentBlazorAuth.Models;
+
+namespace FluentBlazorAuth.Services
+{
+ public interface IUserAccountService
+ {
+ UserAccount? Authenticate(string username, string password);
+ }
+}
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Services/UserAccountService.cs b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Services/UserAccountService.cs
new file mode 100644
index 0000000..2cf2400
--- /dev/null
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/Services/UserAccountService.cs
@@ -0,0 +1,20 @@
+using FluentBlazorAuth.Data;
+using FluentBlazorAuth.Models;
+
+namespace FluentBlazorAuth.Services
+{
+ public class UserAccountService : IUserAccountService
+ {
+ private AppDbContext _appDbContext;
+
+ public UserAccountService(AppDbContext appDbContext)
+ {
+ _appDbContext = appDbContext;
+ }
+
+ public UserAccount? Authenticate(string username, string password)
+ {
+ return _appDbContext.UserAccounts.SingleOrDefault(u => u.UserName == username && u.Password == password);
+ }
+ }
+}
diff --git a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/States/CustomAuthenticationStateProvider.cs b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/States/CustomAuthenticationStateProvider.cs
index d23a610..9f036c9 100644
--- a/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/States/CustomAuthenticationStateProvider.cs
+++ b/FluentBlazorAuth/FluentBlazorAuth/FluentBlazorAuth/States/CustomAuthenticationStateProvider.cs
@@ -1,25 +1,83 @@
-using Blazored.LocalStorage;
+using FluentBlazorAuth.Models;
+using FluentBlazorAuth.Services;
using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.AspNetCore.Http;
using System.Security.Claims;
+using System.Text.Json;
namespace FluentBlazorAuth.States
{
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
- private readonly ILocalStorageService _localStorage;
+ private readonly IUserAccountService _userAccountService;
+ private readonly IHttpContextAccessor _httpContextAccessor;
- public CustomAuthenticationStateProvider(ILocalStorageService localStorage)
+ private const string UserCookieKey = "UserCookie";
+ private UserAccount? _currentUser;
+
+
+ public CustomAuthenticationStateProvider(IUserAccountService userAccountService, IHttpContextAccessor httpContextAccessor)
+ {
+ _userAccountService = userAccountService;
+ _httpContextAccessor = httpContextAccessor;
+
+ LoadUserFromCookie();
+ }
+
+ public override Task GetAuthenticationStateAsync()
{
- _localStorage = localStorage;
+ var identity = _currentUser != null
+ ? new ClaimsIdentity(new[]
+ {
+ new Claim(ClaimTypes.Name, _currentUser.UserName),
+ new Claim(ClaimTypes.Role, _currentUser.Role)
+ }, "apiauth_type")
+ : new ClaimsIdentity();
+
+ var claimPrincipal = new ClaimsPrincipal(identity);
+
+ return Task.FromResult(new AuthenticationState(claimPrincipal));
}
- public override async Task GetAuthenticationStateAsync()
+ public void MarkUserAsAuthenticated(UserAccount userAccount)
{
- var token = await _localStorage.GetItemAsync("authToken");
- if (string.IsNullOrWhiteSpace(token))
- return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
+ _currentUser = userAccount;
+ if (_currentUser != null)
+ {
+ SaveUserCookie();
+ NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
+ }
+ }
- return null;
+ public void MarkUserAsLoggedOut()
+ {
+ _currentUser = null;
+ RemoveUserCookie();
+ NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
+ }
+
+ private void LoadUserFromCookie()
+ {
+ if (_httpContextAccessor.HttpContext?.Request.Cookies.TryGetValue(UserCookieKey, out var jsonUser) == true)
+ {
+ _currentUser = JsonSerializer.Deserialize(jsonUser);
+ }
+ }
+
+ private void SaveUserCookie()
+ {
+ _currentUser.Password = null;
+ var jsonUser = JsonSerializer.Serialize(_currentUser);
+ _httpContextAccessor.HttpContext?.Response.Cookies.Append(UserCookieKey, jsonUser, new CookieOptions
+ {
+ HttpOnly = true,
+ Expires = DateTimeOffset.Now.AddMinutes(5)
+ });
+ }
+
+ private void RemoveUserCookie()
+ {
+ _httpContextAccessor.HttpContext?.Response.Cookies.Delete(UserCookieKey);
}
}
}