1 year ago

#386829

test-img

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

Accepted video resources