如何使用 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" }));
如果您使用的是 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
});
}
我使用 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" }));
如果您使用的是 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
});
}