Make anonymous call to Server in ASP.NET Core hosted Blazor App

I created a Blazor Webassembly app from the included template in VS with Authorization and ASP.NET Core hosted options as shown here:

Create Blazor dialog

I want to be able to make http requests to the server without being authenticated. I changed the code in the WeatherForecastControllerby commenting out the [Authorize] attribute (and even added an [AllowAnonymous] attribute):

//[Authorize] CHANGED
[AllowAnonymous] //CHANGED
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

In the FetchData.razor page, along with other changes noted in the code, I commented out @attribute [Authorize]:

@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using StackOverflowAuthProblem.Shared
@*@attribute [Authorize]*@ @*CHANGED*@
@inject HttpClient Http

@*CHANGED Html removed for brevity*@

<div>Exception message: @exceptionMessage</div>

@code {
    private WeatherForecast[] forecasts;

    string exceptionMessage; //CHANGED

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exceptionMessage = exception.Message; //CHANGED returns an empty string

            exceptionMessage = exception.ToString(); //CHANGED returns
                //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) 
                //at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__9`1[[StackOverflowAuthProblem.Shared.WeatherForecast[],
                //StackOverflowAuthProblem.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
                //at StackOverflowAuthProblem.Client.Pages.FetchData.OnInitializedAsync()
                //in E:\StackOverflow\StackOverflowAuthProblem\StackOverflowAuthProblem\Client\Pages\FetchData.razor:line 53

            //exception.Redirect(); CHANGE
        }
    }
}

The exception I get is in the code above. I suspect the problem is in the App.razor page, but can't figure it out.

Any help?

1 answer

  • answered 2021-01-11 07:45 enet

    Commenting out @attribute [Authorize] can't help you much. The "issue" is with this code:

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

    In the above code BaseAddressAuthorizationMessageHandler is a message handler that attaches access tokens to outgoing System.Net.Http.HttpResponseMessage instances used by your named http client object.

    When you try to access the FetchData page:

    forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
    

    The exception AccessTokenNotAvailableException is thrown as no access token is available. Commenting out the Authorize attribute won't prevent this exception... access token is needed by the http client. That is why you are being redirected to the login page.

    Solution:

    Comment out the Authorize attribute in both the FetchData component page and in the controller

    Comment out @inject HttpClient Http. You're not going to use the instance service.

    In the OnInitializedAsync method create a local instance of the HttpClient service to call the GetFromJsonAsync method. Your code may look like this.

    protected override async Task OnInitializedAsync()
    {
        
        HttpClient Http = new HttpClient();
    
        forecasts = await Http.GetFromJsonAsync<WeatherForecast[]> 
                              ("https://localhost:44331/WeatherForecast");
        
    }
    

    Note: This is a temporary solution. In a real world's application, the code sample I provide should be differently designed...