我正在为Blazor wasm应用程序使用开放式ID连接身份提供程序,并希望将访问令牌附加到this文章中所述的http客户端上。
但是,每当我创建http客户端并尝试使用它时,即使登录,我也会收到AccessTokenNotAvailableException。
这就是我所拥有的:
在Program.cs
// Add service for CustomAuthorizationMessageHandler
builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
// Http client for requests to API
builder.Services.AddHttpClient("API", client =>
{
// Set base address to API url
client.BaseAddress = new Uri("https://localhost:44370");
// Set request headers to application/json
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}).AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
// Auth0 authentication setup
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Auth0", options.ProviderOptions);
options.ProviderOptions.ResponseType = "code";
});
CustomAuthorizationHandler.cs
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://localhost:44370" },
scopes: new[] { "admin" });
}
}
尝试访问api时
try
{
var client = ClientFactory.CreateClient("API");
message = await client.GetStringAsync("api/message");
}
catch (AccessTokenNotAvailableException e)
{
message = "You CANNOT access the api. Please log in";
}
当前,以下代码可在删除Program.cs中的AddHttpMessageHandler调用时从api获取消息,但我不想每次进行api调用时都必须获取访问令牌。 TokenProvider的类型为IAccessTokenProvider,并已插入。
var client = ClientFactory.CreateClient("API");
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, "api/message"))
{
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Value);
var response = await client.SendAsync(requestMessage);
if(response.IsSuccessStatusCode)
{
message = await response.Content.ReadFromJsonAsync<string>();
}
else
{
message = await response.Content.ReadAsStringAsync();
}
}
else
{
message = "You CANNOT access the api. Please log in";
}
}
如何解决此问题,以免每次都不会出现AccessTokenNotAvailableException?
答案 0 :(得分:2)
显然已经指出,有two ways为传出请求配置消息处理程序,建议实现自定义消息处理程序。 再次.........您实现了自定义消息处理程序,以便配置消息处理程序。这是定制的唯一目的。当然,您可以重写SendAsync方法,如果已采取这样的操作,则知道自己在做什么,并且可以正确地执行。但这不是引入错误并实际上使SendAsync无效的方法。
这是自定义消息处理程序的实现:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
-
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://localhost:44370" });
}
}
以上内容解决了您遇到的问题...也就是说,配置了可以忽略的scopes属性(scopes: new[] { "admin" });
)。
以下是一些改进代码的建议: 创建一个名为HttpClient的服务,如下所示。
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>
().CreateClient("ServerAPI"));
像下面这样将其注入到您的组件中:@inject HttpClient Http
并像这样使用它:
protected override async Task OnInitializedAsync()
{
try
{
message= await Http.GetFromJsonAsync<string>("api/message");
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
注意:为了使用GetFromJsonAsync方法,您应该安装 System.Net.Http.Json包
请注意,以上是处理Http请求的正确方法。这包括将用户重定向到登录页面。当然,您可能会产生任何想要显示给用户的消息,但是重定向是正确的方法。
应用上述建议的更改后,您的Program.Main方法应具有以下设置(请注意顺序):
builder.Services.AddScoped<CustomAuthorizationMessageHandler>();
builder.Services.AddHttpClient("ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
builder.Services.AddTransient(sp =>
sp.GetRequiredService<IHttpClientFactory>().CreateClient("ServerAPI"));