Blazor WebAssembly 401即使在获得授权的情况下也未经授权 [英] Blazor WebAssembly 401 Unauthorized even when I am authorized

查看:97
本文介绍了Blazor WebAssembly 401即使在获得授权的情况下也未经授权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Blazor WebAssembly Asp.Net Core托管的PWA ,并将 AspNetCore.Identity 集成到其中.我在客户端创建了 AuthenticationStateProvider ,现在我想允许用户访问需要对其进行授权的控制器.

I am using Blazor WebAssembly Asp.Net Core hosted PWAand integrated the AspNetCore.Identity into it. I created the AuthenticationStateProvider in the Client-Side and now I want to allow the user access to a controller where he needs to be authorized.

我已经通过邮递员进行了测试,已经创建了用户,并以正确的凭据将其作为 aspnetusers 存储在DB中.登录/帐户控制器可以按我的要求工作.

I have tested via postman, the users were been created and stored in DB as aspnetusers with the right credentials. The Login/Account Controller work as I wanted it.

当用户被授权时,在访问授权的控制器请求时,它将在浏览器中告知该异常:

When the user is authorized it tells this exception in the browser when accessing the authorized controller request:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer [100]未处理的异常呈现组件:响应状态代码未指示成功:401(未授权).System.Net.Http.HttpRequestException:响应状态代码不表示成功:401(未授权).

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 -方法):

Startup.cs (ConfigureServices-Method):

...
    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客户端

Program.cs Client-Side


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

具有授权属性的我的控制器:

My Controller with authorize attribute:


    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        [Route("api/[controller]")]
        [ApiController]
        public class ObjectController : ControllerBase
        {
....
    

推荐答案

注意:

  1. 当您的用户尝试访问客户端上受保护(带有Authorize属性注释)的页面时,他应该首先登录或注册.

  1. When your user tries to access a protected (annotated with the Authorize attribute) page on the client he should login first or register.

为了注册,应该将他重定向到一个帐户控制器,在其中您应该创建一个新用户,并将其添加到数据库中(您说过将AspNetCore.Identity集成到其中"),很好...应该用于验证和验证用户的身份.您的帐户控制器还应生成一个Jwt令牌,该令牌应传递到客户端应用程序,并存储在本地存储中.

In order to register, he should be redirected to an Account Controller where you should create a new user, and add it to the database (You said you " integrated the AspNetCore.Identity into it"), which is fine...and should be used to authenticate and verify the user's identity. You account controller should also produce a Jwt Token that should be passed to the client app, and stored in the local storage.

现在,每当用户尝试访问Web Api端点上的受保护资源时,都应从本地存储中检索Jwt令牌,并将其添加到请求标头中.如果您这样做,那么未经授权的回复将成为过去.

Now, whenever your user tries to access protected resources on your Web Api endpoints, you should retrieve the Jwt Token from the local storage, and add it to the request header. If you do so, the Unauthorized response would be something of the past.

自定义AuthenticationStateProvider可能是一个不错的地方,您可以从中管理Jwt令牌存储在本地存储中,并为出站HTTP请求调用检索它.

Custom AuthenticationStateProvider can be a good place from which you can manage storing the Jwt Token in the local storage and retrieving it for outbound HTTP request calls.

以下示例代码阐明了您应该执行的操作:

Here's some sample code to clarify what you should do:

@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令牌

Note: TokenProvider is a custom AuthenticationStateProvider that defines a method called GetTokenAsync that provides (reading the Jwt Token from the local storage and passing it to the calling code) the Jwt Token

希望这对您有帮助...

Hope this helps...

这篇关于Blazor WebAssembly 401即使在获得授权的情况下也未经授权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆