@@ -5,7 +5,7 @@ description: Learn how to secure a Blazor Web App with Windows Authentication.
55monikerRange : ' >= aspnetcore-9.0'
66ms.author : wpickett
77ms.custom : mvc
8- ms.date : 03/25 /2025
8+ ms.date : 09/11 /2025
99uid : blazor/security/blazor-web-app-windows-authentication
1010---
1111# Secure an ASP.NET Core Blazor Web App with Windows Authentication
@@ -88,32 +88,48 @@ The authorization policy is enforced by the `LocalAccountOnly` component.
8888</p>
8989```
9090
91- The ` UserClaims ` component lists the user's claims, which includes the user's Windows security identifiers (SIDs).
91+ The ` UserClaims ` component lists the user's claims and roles, including the user's Windows security identifiers (SIDs) with SID translations .
9292
9393` Components/Pages/UserClaims.razor ` :
9494
9595``` razor
9696@page "/user-claims"
9797@using System.Security.Claims
98- @using Microsoft.AspNetCore.Authorization
99- @attribute [Authorize]
98+ @using System.Security.Principal
99+ @using Microsoft.AspNetCore.Components.QuickGrid
100+
101+ <PageTitle>User Claims & Roles</PageTitle>
102+
103+ <h1>User Claims & Roles</h1>
100104
101- <PageTitle>User Claims</PageTitle>
105+ <QuickGrid Items="claims" Pagination="pagination">
106+ <Paginator State="pagination" />
107+ <PropertyColumn Property="@(p => p.Type)" Sortable="true" />
108+ <PropertyColumn Property="@(p => p.Value)" Sortable="true" />
109+ <PropertyColumn Property="@(p => GetClaimAsHumanReadable(p))" Sortable="true" Title="Translation" />
110+ <PropertyColumn Property="@(p => p.Issuer)" Sortable="true" />
111+ </QuickGrid>
102112
103- <h1>User Claims </h1>
113+ <h1>User Roles </h1>
104114
105- @if (claims .Any())
115+ @if (roles .Any())
106116{
107117 <ul>
108- @foreach (var claim in claims )
118+ @foreach (var role in roles )
109119 {
110- <li><b>@claim.Type:</b> @claim.Value </li>
120+ <li>@role </li>
111121 }
112122 </ul>
113123}
124+ else
125+ {
126+ <p>No roles available.</p>
127+ }
114128
115129@code {
116- private IEnumerable<Claim> claims = [];
130+ private IQueryable<Claim> claims = Enumerable.Empty<Claim>().AsQueryable();
131+ private IEnumerable<string> roles = Enumerable.Empty<string>();
132+ PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
117133
118134 [CascadingParameter]
119135 private Task<AuthenticationState>? AuthState { get; set; }
@@ -126,7 +142,38 @@ The `UserClaims` component lists the user's claims, which includes the user's Wi
126142 }
127143
128144 var authState = await AuthState;
129- claims = authState.User.Claims;
145+
146+ claims = authState.User.Claims.AsQueryable();
147+
148+ roles = authState.User.Claims
149+ .Where(claim => claim.Type == ClaimTypes.Role)
150+ .Select(claim => claim.Value);
151+ }
152+
153+ private string GetClaimAsHumanReadable(Claim claim)
154+ {
155+ if (!OperatingSystem.IsWindows() ||
156+ claim.Type is not (ClaimTypes.PrimarySid or ClaimTypes.PrimaryGroupSid
157+ or ClaimTypes.GroupSid))
158+ {
159+ // We're either not on Windows or not dealing with a SID Claim that
160+ // can be translated
161+ return string.Empty;
162+ }
163+
164+ SecurityIdentifier sid = new SecurityIdentifier(claim.Value);
165+
166+ try
167+ {
168+ // Throw an exception if the SID can't be translated
169+ var account = sid.Translate(typeof(NTAccount));
170+
171+ return account.ToString();
172+ }
173+ catch (IdentityNotMappedException)
174+ {
175+ return "Could not be mapped";
176+ }
130177 }
131178}
132179```
0 commit comments