Reputation: 326
I'm writing a Blazor server-side app with Windows Authentication enabled in the project.
I'm unable to use Role/Policy based authentication (I don't have access to change users roles/policies) and instead will be grabbing a set of usernames from a SQL database to check against the current user as to what parts of the NavMenu they can access.
I'm struggling to get the windows username available to all components and accessible from within the @code section though.
I've seen in the App.razor they use CascadingAuthenticationState component and an AuthoriseView component
I know you can use @context.User.Identity.Name to display the username but I'm not sure how to access the @context from within a @code section to get the username.
I've also tried this code and in the app which displays the username successfully:
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private string _authMessage;
private async Task LogUsername()
{
var authState = await authenticationStateTask;
var user = authState.User;
if (user.Identity.IsAuthenticated)
{
_authMessage = $"{user.Identity.Name} is authenticated.";
}
else
{
_authMessage = "The user is NOT authenticated.";
}
}
But I don't like the idea of repeating something like this async code in every component.
My simple idea was to create an "AuthorisationService" class and register it as a singleton. This would get the set of usernames from SQL and the current user at the outset when the page is first loaded and the logic of checking can live in there.
I'd inject it into every component and for the NavMenu I can have if-statements as to who can access what making them visible or not .
If anyone can shed some light on how to get the windows username in this way (or a better way if one exists as I'm just learning and completely new to Blazor) that would be great!
Many Thanks
Nick
Upvotes: 0
Views: 2021
Reputation: 2881
In order to cascade the UserName to all components you need to create a class to get the userName like this:
public class UserInfo
{
private readonly AuthenticationStateProvider authenticationStateProvider;
public UserInfo(AuthenticationStateProvider authenticationStateProvider)
{
this.authenticationStateProvider = authenticationStateProvider;
}
public async Task<string> GetUserName()
{
var authState = await authenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
return user?.Identity?.Name ?? "Pitza man";
}
}
Now you need to register this class in Startup
services.AddScoped<UserInfo>();
Then in your main layout you can add a cascading value
@inherits LayoutComponentBase
@inject UserInfo _user
<CascadingValue Value="_user.GetUserName()" Name="UserName">
@Body
</CascadingValue>
Then in your component can get this value:
@code {
[CascadingParameter(Name = "UserName")] public string UserName { get; set; }
}
Upvotes: 5
Reputation: 197
I had a use-case for getting info from the HttpContext related to JWT tokens. Serverside can be confusing, because it is a black-box that works through signal R, but this works for me. You can modify for your own use-case.
_Host.cshtml
<body>
@{
var token = await HttpContext.GetTokenAsync("access_token");
}
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" param-AccessToken="token" />
</app>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
</body>
App.Razor
<CascadingValue Name="AccessToken" Value="AccessToken">
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>
</CascadingValue>
@code{
[Parameter] public string AccessToken { get; set; }
}
You can read more about this (https://github.com/dotnet/aspnetcore/issues/18183)
Upvotes: 1