1 year ago
#386829
cemil
Blazor server side authentication require all-browser tabs
I used an authentication for a blazor server side app
I created a login page and used authorized pages.I authenticated at login page.These worked properly but, when I opened a new tab app we have to authenticate again.It is interesting that in first page I yet authenticated. I want to login all non private tabs on browser.
Codes are below
startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthenticationCore();
services.AddAuthorizationCore();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
services.AddScoped<ProtectedSessionStorage>();
services.AddSingleton<UserAccountService>();
services.AddScoped<AuthenticationStateProvider, AuthStateProvider>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
AuthStateProvider:
public class AuthStateProvider : AuthenticationStateProvider
{
private readonly ProtectedSessionStorage sessionStorage;
private ClaimsPrincipal anonymous = new ClaimsPrincipal(new ClaimsIdentity());
public AuthStateProvider(ProtectedSessionStorage sessionStorage)
{
this.sessionStorage = sessionStorage;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
try
{
var userSessionStorageResult = await sessionStorage.GetAsync<UserSession>("UserSession");
var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
if (userSession == null)
{
return await Task.FromResult(new AuthenticationState(anonymous));
}
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Name,userSession.Username),
new Claim(ClaimTypes.Role,userSession.Role)
}, "CustomAuth"));
return await Task.FromResult(new AuthenticationState(claimsPrincipal));
}
catch (Exception ex)
{
return await Task.FromResult(new AuthenticationState(anonymous));
}
}
public async Task UpdateAuthenticationState(UserSession userSession)
{
ClaimsPrincipal claimsPrincipal;
if (userSession != null)
{
await sessionStorage.SetAsync("UserSession", userSession);
claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Name,userSession.Username),
new Claim(ClaimTypes.Role,userSession.Role)
}));
}
else
{
await sessionStorage.DeleteAsync("UserSession");
claimsPrincipal = anonymous;
}
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal)));
}
}
Login.Razor:
private class Model
{
public string Username { get; set; }
public string Password { get; set; }
}
private Model model = new Model();
private async Task Authenticate()
{
var userAccount = userAccountService.GetByUserName(model.Username);
if (userAccount == null || userAccount.Password != model.Password)
{
await js.InvokeVoidAsync("alert", "Invalid User Name or Password");
return;
}
var customAuthStateProvider = (AuthStateProvider)authStateProvider;
await customAuthStateProvider.UpdateAuthenticationState(new UserSession
{
Username = userAccount.Username,
Role=userAccount.Role
});
navManager.NavigateTo("/", true);
}
Counter.Razor:
@page "/counter"
@attribute [Authorize(Roles = "admin,user")]
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
authentication
authorization
blazor
blazor-server-side
0 Answers
Your Answer