Blazor WebAssembly 401 未经授权,即使我已获得授权
Blazor WebAssembly 401 Unauthorized even when I am authorized
我正在使用 Blazor WebAssembly Asp.Net Core hosted PWA
并将 AspNetCore.Identity
集成到其中。我在客户端创建了 AuthenticationStateProvider
,现在我想允许用户访问他需要被授权的控制器。
我已经通过邮递员进行了测试,用户是使用正确的凭据创建并存储在数据库中的 aspnetusers
。 Login/Account 控制器按我的要求工作。
当用户获得授权时,它会在访问授权控制器请求时在浏览器中告知此异常:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Response status code does not indicate success: 401 (Unauthorized).
System.Net.Http.HttpRequestException: Response status code does not
indicate success: 401 (Unauthorized).
Startup.cs(ConfigureServices
-方法):
...
serviceCollection.AddDbContext<SQLiteTestDbContext>(options =>
{
options.UseSqlite(config["ConnectionStrings:SQLiteTestConnection"]);
});
serviceCollection.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<SQLiteTestDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
};
});
services.AddHttpContextAccessor();
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseAuthentication();
app.UseAuthorization();
...
}
Program.cs 客户端
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Logging.SetMinimumLevel(LogLevel.Warning);
//Registering Shared-Library models
builder.Services.AddScoped<ObjectModel>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
builder.Services.AddScoped<IAuthService, AuthService>();
//Registered BlazorContextMenu Service
builder.Services.AddBlazorContextMenu();
//Registering FileReader service, for image upload -> Azure
builder.Services.AddFileReaderService(options => options.UseWasmSharedBuffer = true);
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
我的具有授权属性的控制器:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
[ApiController]
public class ObjectController : ControllerBase
{
....
注:
当您的用户尝试访问客户端上的受保护(使用授权属性注释)页面时,他应该先登录或注册。
为了注册,他应该被重定向到一个帐户控制器,您应该在其中创建一个新用户,并将其添加到数据库中(你说你“将 AspNetCore.Identity 集成到it"),这没问题...应该用于验证和验证用户的身份。您的帐户控制器还应生成一个 Jwt 令牌,该令牌应传递给客户端应用程序并存储在本地存储中。
现在,每当您的用户尝试访问 Web Api 端点上的受保护资源时,您应该从本地存储中检索 Jwt 令牌,并将其添加到请求中 header.如果您这样做,未经授权的响应将成为过去。
自定义 AuthenticationStateProvider 是一个很好的地方,您可以从中管理将 Jwt 令牌存储在本地存储中并检索它以进行出站 HTTP 请求调用。
这里有一些示例代码来阐明您应该做什么:
@code {
WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
var token = await TokenProvider.GetTokenAsync();
forecasts = await Http.GetJsonAsync<WeatherForecast[]>(
"api/WeatherForecast",
new AuthenticationHeaderValue("Bearer", token));
}
}
注意:TokenProvider 是一个自定义的 AuthenticationStateProvider,它定义了一个名为 GetTokenAsync 的方法,该方法提供(从本地存储读取 Jwt 令牌并将其传递给调用代码)Jwt 令牌
希望这对您有所帮助...
我正在使用 Blazor WebAssembly Asp.Net Core hosted PWA
并将 AspNetCore.Identity
集成到其中。我在客户端创建了 AuthenticationStateProvider
,现在我想允许用户访问他需要被授权的控制器。
我已经通过邮递员进行了测试,用户是使用正确的凭据创建并存储在数据库中的 aspnetusers
。 Login/Account 控制器按我的要求工作。
当用户获得授权时,它会在访问授权控制器请求时在浏览器中告知此异常:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Response status code does not indicate success: 401 (Unauthorized). System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
Startup.cs(ConfigureServices
-方法):
...
serviceCollection.AddDbContext<SQLiteTestDbContext>(options =>
{
options.UseSqlite(config["ConnectionStrings:SQLiteTestConnection"]);
});
serviceCollection.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<SQLiteTestDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
};
});
services.AddHttpContextAccessor();
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseAuthentication();
app.UseAuthorization();
...
}
Program.cs 客户端
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Logging.SetMinimumLevel(LogLevel.Warning);
//Registering Shared-Library models
builder.Services.AddScoped<ObjectModel>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
builder.Services.AddScoped<IAuthService, AuthService>();
//Registered BlazorContextMenu Service
builder.Services.AddBlazorContextMenu();
//Registering FileReader service, for image upload -> Azure
builder.Services.AddFileReaderService(options => options.UseWasmSharedBuffer = true);
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
我的具有授权属性的控制器:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
[ApiController]
public class ObjectController : ControllerBase
{
....
注:
当您的用户尝试访问客户端上的受保护(使用授权属性注释)页面时,他应该先登录或注册。
为了注册,他应该被重定向到一个帐户控制器,您应该在其中创建一个新用户,并将其添加到数据库中(你说你“将 AspNetCore.Identity 集成到it"),这没问题...应该用于验证和验证用户的身份。您的帐户控制器还应生成一个 Jwt 令牌,该令牌应传递给客户端应用程序并存储在本地存储中。
现在,每当您的用户尝试访问 Web Api 端点上的受保护资源时,您应该从本地存储中检索 Jwt 令牌,并将其添加到请求中 header.如果您这样做,未经授权的响应将成为过去。
自定义 AuthenticationStateProvider 是一个很好的地方,您可以从中管理将 Jwt 令牌存储在本地存储中并检索它以进行出站 HTTP 请求调用。
这里有一些示例代码来阐明您应该做什么:
@code {
WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
var token = await TokenProvider.GetTokenAsync();
forecasts = await Http.GetJsonAsync<WeatherForecast[]>(
"api/WeatherForecast",
new AuthenticationHeaderValue("Bearer", token));
}
}
注意:TokenProvider 是一个自定义的 AuthenticationStateProvider,它定义了一个名为 GetTokenAsync 的方法,该方法提供(从本地存储读取 Jwt 令牌并将其传递给调用代码)Jwt 令牌
希望这对您有所帮助...