如何使用 blazor 前端 http 请求附加令牌

How to attach a token with blazor frontend http request

我使用 blazor 作为前端,api 已完成 JWT 配置。 前端可以创建用户帐户并登录 API,但现在我的前端 httpclient 没有设置 JWT 令牌,所以如果我在 Api 控制器中设置 [授权],前端无法访问它。

api程序代码如下

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"]))
        };
    }); 

控制器代码如下

   [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);
    }

前端blazor程序代码如下

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

下面是“CustomAuthorizationMessageHandler”代码。

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

    }
}

}

访问服务如下

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

现在当我调用 GetQuizzesDetailsAsync() 这个服务时,它给我一个错误。

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)

我的代码有什么问题?我想我只是将登录用户的令牌附加到http请求,它就可以成功访问,有什么简单的方法可以做到这一点吗?

您似乎不需要 CustomAuthorizationMessageHandler。

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

Configure the HttpClient handler

如果您使用的是 Blazor WebAssembly,则需要从服务中的 Microsoft.AspNetCore.Components.WebAssembly.Authentication 命名空间注入 IAccessTokenProvider 并从那里获取令牌。获得令牌后,您可以将令牌值传递给您的 httpclient 的授权 header。

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
    });
 }