Edit

Share via


Secure an ASP.NET Core Blazor Web App with Windows Authentication

This article describes how to secure a Blazor Web App with Windows Authentication using a sample app. For more information, see Configure Windows Authentication in ASP.NET Core.

The app specification for the Blazor Web App:

Sample app

Access the sample through the latest version folder in the Blazor samples repository with the following link. The sample is in the BlazorWebAppWinAuthServer folder for .NET 9 or later.

View or download sample code (how to download)

Configuration

The sample app doesn't require configuration to run locally.

When deployed to a host, such as IIS, the app must adopt impersonation to run under the user's account. For more information, see Configure Windows Authentication in ASP.NET Core.

Sample app code

Inspect the Program file in the sample app for the following API calls.

AddAuthentication is called using the NegotiateDefaults.AuthenticationScheme authentication scheme. AddNegotiate configures the AuthenticationBuilder to use Negotiate (also known as Windows, Kerberos, or NTLM) authentication, and the authentication handler supports Kerberos on Windows and Linux servers:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate();

AddAuthorization adds authorization policy services. AuthorizationOptions.FallbackPolicy sets the fallback authorization policy, which is set to the default policy (AuthorizationOptions.DefaultPolicy). The default policy requires an authenticated user to access the app:

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
});

AddCascadingAuthenticationState adds cascading authentication state to the service collection. This is equivalent to placing a CascadingAuthenticationState component at the root of the app's component hierarchy:

builder.Services.AddCascadingAuthenticationState();

An authorization policy is added for a Windows security identifier (SID). The S-1-5-113 well-known SID in the following example indicates that the user is a local account, which restricts network sign-in to local accounts instead of "administrator" or equivalent accounts:

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("LocalAccount", policy =>
        policy.RequireClaim(
            "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid",
            "S-1-5-113"));   

The authorization policy is enforced by the LocalAccountOnly component.

Components/Pages/LocalAccountOnly.razor:

@page "/local-account-only"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize("LocalAccount")]

<h1>Local Account Only</h1>

<p>
    You can only reach this page by satisfying the
    <code>LocalAccount</code> authorization policy.
</p>

The UserClaims component lists the user's claims, which includes the user's Windows security identifiers (SIDs).

Components/Pages/UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = [];

    [CascadingParameter]
    private Task<AuthenticationState>? AuthState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

Additional resources