Sanj
Sanj

Reputation: 3870

Blazor Authentication - Http calls does work for anonymous

I have been playing with blazor with .net 5.0. I am stuck with a simple but annoying issue: I am trying to load data from API but every call to the Server blazor expects the user to be signed in.

I understood if we took out [Authorize] tag from the API controller and don't have @attribute [Authorize] in the razor page, and that would be it. But I am struggling to understand why my API call still expects AccessToken in protected override async Task OnInitializedAsync() the error messages don't say much around why.

Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessTokenNotAvailableException: ''
at Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)

I haven't touched the App. cs file of the web assembly..

Can anyone help please.

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    @if (!context.User.Identity.IsAuthenticated)
                    {
                        <RedirectToLogin />
                    }
                    else
                    {
                        <p>You are not authorized to access this resource.</p>
                    }
                </NotAuthorized>
                <Authorizing>
                    <h4>Authentication in progress...</h4>
                </Authorizing>                
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Upvotes: 4

Views: 4222

Answers (2)

Sanj
Sanj

Reputation: 3870

I figured the solution ... should have looked at it first.

it was actually the App.CS fill in the Client Project. Http endpoint is initiated there, and by default the code-gen adds BaseAddressAuthorizationMessageHandler to the httpclient.

builder.Services.AddHttpClient("private", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
       .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

how I solved it was using named clients one for Private and one for Public like so

builder.Services.AddHttpClient("private", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddHttpClient("public", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

and in pages inject IHttpClientFactory

@inject IHttpClientFactory ClientFactory

and create a named client from the factory.

var client = ClientFactory.CreateClient("public");

This worked.

Upvotes: 9

Qudus
Qudus

Reputation: 1520

I think it's because you have CascadingAuthenticationState encapsulating both Foundcontext and NotFound since what it does is to pass authorization information down to other components. So, wrapping it around all your components prevents access to unauthorized users. Try this instead

<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
                @if (!context.User.Identity.IsAuthenticated)
                {
                    <RedirectToLogin />
                }
                else
                {
                    <p>You are not authorized to access this resource.</p>
                }
            </NotAuthorized>
            <Authorizing>
                <h4>Authentication in progress...</h4>
            </Authorizing>                
        </AuthorizeRouteView>
    </Found>
    <NotFound>
        <CascadingAuthenticationState>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        <CascadingAuthenticationState>
    </NotFound>
</Router>

Upvotes: -1

Related Questions