Home > Net >  How to attach a token with blazor frontend http request
How to attach a token with blazor frontend http request

Time:03-27

I use blazor as frontend , api has completed with JWT configuration. Frontend can create user account and login to API, but now my frontend httpclient is not setting with JWT token, so if I set [Authorised] in Api controller, Frontend can not access it.

The api program code is below

builder.Services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<DBContext>();//add user model,role model and connect toDbcontext
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters() {
            ValidateIssuer = true,
            ValidIssuer = builder.Configuration["Authentication:Issuer"],
            ValidateAudience = true,
            ValidAudience = builder.Configuration["Authentication:Audience"],
            ValidateLifetime = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Authentication:SecretKey"]))
        };
    }); 

and contorller code is below

   [HttpGet("all")]
    [HttpHead]
    //[Authorize(AuthenticationSchemes = "Bearer")]
    [Authorize]
    public async Task<ActionResult<IEnumerable<Quiz>>> GetQuizzesDetailsAsync() {
     
       var quizzes= await _quizzesRepository.GetQuizzesDetailsAsync( );
        var quizDtos=_mapper.Map<IEnumerable<QuizOverviewDto>>(quizzes);
        return Ok(quizDtos);
    }

the frontend blazor program code is below

builder.Services.AddHttpClient<IQuizService, QuizService>(
      client => client.BaseAddress = new Uri("https://localhost:7172"))
    .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();

and "CustomAuthorizationMessageHandler" code is below.

public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler {
    public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
        NavigationManager navigationManager)
        : base(provider, navigationManager) {
        ConfigureHandler(
           authorizedUrls: new[] { "https://localhost:7172" });

    }
}

}

access service is below

        public async Task<IEnumerable<QuizOverviewDto>> GetQuizzesDetailsAsync() {         
            return await JsonSerializer.DeserializeAsync<IEnumerable<QuizOverviewDto>>(
await _httpClient.GetStreamAsync("api/quizzes/all"),
new JsonSerializerOptions {
    PropertyNameCaseInsensitive = true
});
        } 

now When I call GetQuizzesDetailsAsync() this service , it give me an error below.

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Unable to resolve service for type 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider' while attempting to activate 'PerfectPoliciesFE.CustomAuthorizationMessageHandler'. System.InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider' while attempting to activate 'PerfectPoliciesFE.CustomAuthorizationMessageHandler'. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)

What the problem in my code? I think I only attach the logined user's token to http request, and it can access successfully, is any simple way to do this ?

CodePudding user response:

You don't appear to need CustomAuthorizationMessageHandler.

builder.Services.AddHttpClient<QuizService>(
      client => client.BaseAddress = new Uri("https://localhost:7172"))
        .AddHttpMessageHandler(sp => sp.GetRequiredService<AuthorizationMessageHandler>()
        .ConfigureHandler(
            authorizedUrls: new[] { "https://localhost:7172" }));

see Configure the HttpClient handler

CodePudding user response:

If you're using Blazor WebAssembly, you need to inject the IAccessTokenProvider from the Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace inside your service and get the token from there. Once you have the token, you can pass the token value to the Authorization header of your httpclient.

private readonly IAccessTokenProvider _tokenProvider;
private readonly HttpClient _httpClient;

public class QuizService(IAccessTokenProvider tokenProvider, HttpClient httpClient)
{
    _tokenProvider = tokenProvider;
    _httpClient = httpClient;
}

private async Task RequestAuthToken()
{
    var requestToken = await _tokenProvider.RequestAccessToken();
    requestToken.TryGetToken(out var token);
    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Value);
}

public async Task<IEnumerable<QuizOverviewDto>> GetQuizzesDetailsAsync() 
{  
  await RequestAuthToken();
  return await JsonSerializer.DeserializeAsync<IEnumerable<QuizOverviewDto>>(
    await _httpClient.GetStreamAsync("api/quizzes/all"),
    new JsonSerializerOptions {
        PropertyNameCaseInsensitive = true
    });
 } 
  • Related