Is there a way to Authenticate a user before downloading the client side Blazor app?
U

2

6

I am currently working on a Blazor web assembly project that is core hosted. The project is split up into three parts, Client, Server and Shared. The way I understand it is that when a user hits the web address they will download the client side package and run it on their web browser. I would like to know if there is a way to Authenticate a user before they download the client side package?

I have successfully implemented a login process on the client side using the microsoft documentation: Secure an ASP.NET Core Blazor WebAssembly hosted app with Azure Active Directory

but I would like to take it a step further and see if I can authenticate a user before downloading the client side package.

I have spent most of my time adding authentication code to Server.Startup.cs assuming that when a user navigates to my website they would make a request to the server for the client side package.

Has anyone tried doing anything like this? Thanks for any advice

Unconscious answered 18/6, 2021 at 4:46 Comment(0)
I
2

I don't think this is possible per se. But you could try adding a Blazor Server app that is responsible for authentication (since it loads way faster), and then switch to the Wasm app using an approach similar to what's shown in this article:https://itnext.io/blazor-switching-server-and-webassembly-at-runtime-d65c25fd4d8

Ignatz answered 18/6, 2021 at 13:18 Comment(4)
Thanks for the suggestion, that technique did cross my mind, having a basic redirect site infront of the wasm site. but I was hoping there would be a cleaner approach.Unconscious
Well it's kinda obvious that you can't process the login if the site code doesn't loadIgnatz
But there is a request made for the download of the client side app. I wanted to catch the request part and assumed it was a server side thing. I just dont know exactly where I can catch the initial request for the client side download.Unconscious
In a middleware.Ignatz
M
1

I just figured out how to do this in .NET 7.0 RC1 (I don't see why it wouldn't work in 5.0 and 6.0 too, but haven't tested). So far it seems to work, but will see if I come across any issues...

In Program.cs:

// so I can access login page static assets. See extension method below
app.UseStaticAlwaysWhenPathsUniversal();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

// restrict Blazor WASM client to users in specific role(s). See extension method below
app.UseRestrictPagesForNonPrivilegedUsers(Authentication.LoginPath);
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
/// <summary>
/// I don't want Blazor WASM accessible (at all, not even loadable) before logging in as employee user, but still make static assets
/// accessible to identity pages (e.g. login). In the future we may have customers logging in but they should not
/// be able to access Blazor WASM client.
/// </summary>
/// <param name="app">The web application</param>
public static void UseStaticAlwaysWhenPathsUniversal(this WebApplication app)
{
    app.UseWhen(
        AlwaysAllowStaticContent, // see method below
        a => a.UseStaticFiles()
    );
}
/// <summary>
/// Redirect to specified page whenever non-privileged user tries to access an address that is not allowed.
/// Use for customers in the future. Don't allow them to access Blazor WASM client.
/// </summary>
/// <param name="app">The web application</param>
/// <param name="redirectTo">The path to redirect to if the logged in user tries to access a path
/// that is not in 'allowedPaths'</param>
public static void UseRestrictPagesForNonPrivilegedUsers(this WebApplication app, string redirectTo)
{
    app.Use(async (context, next) =>
    {
        var isEmployee = context.User.HasClaim(claim => claim.Type == ClaimTypes.Role && claim.Value == "Employee");
        if (isEmployee || AlwaysAllowStaticContent(context))
        {
            await next.Invoke();
            return;
        }

        context.Response.Redirect(redirectTo);
    });
}
private static bool AlwaysAllowStaticContent(HttpContext context)
{
    return context.Request.Path.StartsWithSegments("/connect") || // my login/logout pages start with /connect
           context.Request.Path.StartsWithSegments("/_content") ||
           context.Request.Path.StartsWithSegments("/lib") ||
           context.Request.Path.StartsWithSegments("/favicon.ico");
}

Update 1: To simplify things and just prevent access to framework files (i.e. my dll files etc), I changed my code to this. The down-side to this approach is that if a non-privileged user is logged in and tries to navigate to the Blazor WASM site, the "loading" page will show but then it will just freeze on that page. In Program.cs:

app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

// restrict Blazor WASM client to users in a specific role. See extension method below
app.UseBlockFrameworkFilesForNonPrivilegedUsers("Employee");
app.UseBlazorFrameworkFiles();
/// <summary>
/// Forbid access to Blazor WASM framework files for a user that is not in specified <paramref name="privilegedRole"/>.
/// </summary>
/// <param name="app">The web application</param>
/// <param name="privilegedRole">The role a user must have to access Blazor WASM</param>
public static void UseBlockFrameworkFilesForNonPrivilegedUsers(this WebApplication app, string privilegedRole)
{
    app.Use(async (context, next) =>
    {
        var isInPrivilegedRole = context.User.HasClaim(claim => claim.Type == ClaimTypes.Role && claim.Value == privilegedRole);
        if (isInPrivilegedRole || !IsFrameworkPath(context))
            await next.Invoke();
        else
            context.Response.StatusCode = StatusCodes.Status403Forbidden;
    });
}
Muro answered 21/9, 2022 at 6:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.