当在服务器端的 Blazor 下使用 SignInManager.SignInAsync(.......) 时,它会引发异常

San*_*ain 7 c# asp.net-core blazor-server-side

我正在学习服务器端 blazor 并尝试学习身份验证。每当我使用 SignInManager.SignInAsync(.......) 时,它都会引发以下异常:

System.InvalidOperationException:无法修改响应标头,因为响应已开始。 在 Microsoft.AspNetCore.HttpSys.Internal.HeaderCollection.ThrowIfReadOnly() 在 Microsoft.AspNetCore.HttpSys.Internal.HeaderCollection.set_Item(String key, StringValues value) 在 Microsoft.AspNetCore.Http.ResponseCookies.Append(String key, String value, CookieOptions 选项) 位于 Microsoft.AspNetCore.Authentication.Cookies.ChunkingCookieManager.AppendResponseCookie(HttpContext context、String key、String value、CookieOptions options) 位于 Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler.HandleSignInAsync(ClaimsPrincipal 用户、AuthenticationProperties 属性) 位于 Microsoft。 AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext 上下文、字符串方案、ClaimsPrincipal 主体、AuthenticationProperties 属性) 位于 Microsoft.AspNetCore.Identity.SignInManager 1.SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable1 extraClaims),位于 C:\my_work\Blazor_learning\GroupMembersInfo 中的 GroupMembersInfo.Pages.RegisterUser.Register() \Pages\RegisterUser.razor:第 52 行位于 Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(任务任务)位于 Microsoft.AspNetCore.Components.Forms.EditForm.HandleSubmitAsync()
位于 Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(任务任务) )在 Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(任务 taskToHandle)

我认为异常是从我突出显示的方法中抛出的。那么我该如何缓解这个问题。这是我的代码

启动程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using GroupMembersInfo.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;

namespace GroupMembersInfo
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContextPool<AppDbContext>(
                options => options.UseSqlServer(Configuration.GetConnectionString("GMIDbConnection")));

            services.AddIdentity<IdentityUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<AppDbContext>();

            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
            services.AddSingleton<WeatherForecastService>();

            services.ConfigureApplicationCookie(options =>
            {
                options.SlidingExpiration = true;

                options.Events.OnRedirectToLogin = cxt =>
                {
                    cxt.Response.StatusCode = 401;
                    return Task.CompletedTask;
                };

                options.Events.OnRedirectToAccessDenied = cxt =>
                {
                    cxt.Response.StatusCode = 403;
                    return Task.CompletedTask;
                };

                options.Events.OnRedirectToLogout = cxt => Task.CompletedTask;
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

登录组件代码

@page "/loginPage"

@using Microsoft.AspNetCore.Identity;
@using GroupMembersInfo.Data;

@inject UserManager<IdentityUser> UserManager
@inject SignInManager<IdentityUser> SignInManager
@inject NavigationManager NavigationManager

<h3>Log In</h3>

<div class="row">
    <div class="col-md-12">
        <EditForm Model="@RegisterUserModel" OnValidSubmit="@LogIn">
            <div class="form-group">
                <label>Iser Id: </label>
                <input @bind-value="RegisterUserModel.Email" class="form-control" />
            </div>
            <div class="form-group">
                <label>Password: </label>
                <input @bind-value="RegisterUserModel.Password" class="form-control" />
            </div>
            <div class="form-group">
                <button type="submit">Submit</button>
            </div>
        </EditForm>
    </div>
</div>

@code {
    public RegisterUserModel RegisterUserModel { get; set; } = new RegisterUserModel();

    public async Task LogIn()
    {
        var user = new IdentityUser
        {
            UserName = RegisterUserModel.Email
        };

        user.PasswordHash = SignInManager.UserManager.PasswordHasher.HashPassword(user, RegisterUserModel.Password);

        await SignInManager.SignInAsync(user, isPersistent: false);

        NavigationManager.NavigateTo("/");
    }
}
Run Code Online (Sandbox Code Playgroud)

Man*_*ari 2

问题出在下面两行:

await SignInManager.SignInAsync(user, isPersistent: false);

NavigationManager.NavigateTo("/");
Run Code Online (Sandbox Code Playgroud)

在 SignInAsync 完成之前,页面将导航到下一页。这就是 SignInAsync 无法完成其工作的原因。

解决方案:

如果您在 NavigationManager.NavigateTo 之前添加 return 语句,应该可以解决该问题。

这是因为在等待的操作完成之前该方法无法返回。

return NavigationManager.NavigateTo("/");
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。