Htttp 400 Bad Request 请求标头太长

问题描述 投票:0回答:1

我目前正在使用 Asp.net core 5.0 和 Identity server 4 开发一个应用程序。我的 OIDC 身份验证流程由

Microsoft.AspNetCore.Authentication.OpenIdConnect
处理。我将应用程序部署到 IIS 中,并且看到了登录屏幕。但登录后我收到 Http 400 Bad request 错误。Error。我检查了我的应用程序 cookie,它包含许多
AspNetCore.OpenIdConnect.Nonce
cookie。我删除了 cookie,但没有解决我的问题。处理这个解决方案的正确解决方案是什么。我尝试过this但对我没有帮助。我将分享下面的代码

MVC Startup.cs

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

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            }).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
            services.AddScoped<RenewToken>();
            services.AddAuthorization(options =>
            {
                options.AddPolicy("CreatePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RC", "UC")));
                options.AddPolicy("ReadPolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RR", "UR")));
            });
            services.AddControllersWithViews();
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            }).AddCookie("Cookies", options =>
            {
                options.Cookie.Name = "Cookies";
                options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
                options.SlidingExpiration = true;
            }).AddOpenIdConnect("oidc", options =>
                {
                    options.BackchannelHttpHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = delegate { return true; } };
                    options.Authority = Configuration.GetSection("API:IDS4").Value;
                    options.SignInScheme = "Cookies";
                    options.SignedOutRedirectUri = Configuration.GetSection("API:WebClient").Value + "/signout-callback-oidc";
                    options.RequireHttpsMetadata = true;
                    options.ClientId = "mvc";
                    options.ClientSecret = "*****";
                    options.ResponseType = "code";
                    options.UsePkce = true;
                    options.Scope.Add("profile");
                    options.Scope.Add("mcApi");
                    options.Scope.Add("Api1");
                    options.Scope.Add("Api2");
                    options.Scope.Add("Api3");
                    options.Scope.Add("Api4");
                    options.Scope.Add("Api5");
                    options.Scope.Add("Api6");
                    options.Scope.Add("Api7");
                    options.Scope.Add("offline_access");
                    options.GetClaimsFromUserInfoEndpoint = true;
                    options.SaveTokens = true;
                    options.Events.OnRedirectToIdentityProvider = context =>
                    {
                        context.ProtocolMessage.Prompt = "login";
                        return Task.CompletedTask;
                    };

                    options.Events = new OpenIdConnectEvents
                    {
                        OnRemoteFailure = (context) =>
                        {
                            context.Response.Redirect("/");
                            context.HandleResponse();

                            return Task.CompletedTask;
                        }
                    };
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        RoleClaimType = JwtClaimTypes.Role
                    };

                });

            
            services.AddHttpClient<IAdminService, AdminService>();
            services.AddSingleton<DataProtectionPurposeStrings>();
            services.AddSingleton<GlobalConstants>();
        }

        private bool AuthorizeAccess(AuthorizationHandlerContext context, string roleClaim, string userClaim)
        {
            return context.User.HasClaim(claim => claim.Type == roleClaim && claim.Value == "True") &&
                   context.User.HasClaim(claim => claim.Type == userClaim && claim.Value == "True") ||
                   context.User.IsInRole("MyAdmin");
        }

        // 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("/Home/Error");                
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
            app.UseRouting();

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

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

        }
    }

身份服务器启动.cs

public class Startup
    {
        public IWebHostEnvironment Environment { get; }
        public IConfiguration Configuration { get; }
        public Startup(IWebHostEnvironment environment, IConfiguration configuration)
        {
            Environment = environment;
            Configuration = configuration;
        }
        // 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.AddControllersWithViews();

            /****Register asp.net core Identity DBConetexts***/
            var idenConnectionString = Configuration["DbContextSettings:IdentityConnectionString"];
            
            var dbPassword = Configuration["DbContextSettings:DbPassword"];
            var builder = new NpgsqlConnectionStringBuilder(idenConnectionString)
            {
                Password = dbPassword
            };
            

            services.AddDbContext<IdentityDBContext>(opts => opts.UseNpgsql(builder.ConnectionString));

            services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
            {
                options.Password.RequiredLength = 8;
                options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+ ";
                options.SignIn.RequireConfirmedEmail = false;
                options.User.RequireUniqueEmail = false;
            }).AddRoles<ApplicationRole>().AddEntityFrameworkStores<IdentityDBContext>()
            .AddDefaultTokenProviders();

            /****Identity Server implementation with asp.net core Identity***/

            var idsServerConnectionString = Configuration["DbContextSettings:IdentityServer4ConnectionString"];
            var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
            var idsServerdbPassword = Configuration["DbContextSettings:DbPassword"];
            var idsServerbuilder = new NpgsqlConnectionStringBuilder(idsServerConnectionString)
            {
                Password = dbPassword
            };
            
            var idBuilder = services.AddIdentityServer(options =>
              {
                  options.Events.RaiseErrorEvents = true;
                  options.Events.RaiseInformationEvents = true;
                  options.Events.RaiseFailureEvents = true;
                  options.Events.RaiseSuccessEvents = true;
                  options.UserInteraction.LoginUrl = "/Account/Login";
                  options.UserInteraction.LogoutUrl = "/Account/Login";
                  options.Authentication = new AuthenticationOptions()
                  {
                      CookieLifetime = TimeSpan.FromMinutes(10),
                      CookieSlidingExpiration = true
                  };
              })
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b => b.UseNpgsql(idsServerbuilder.ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => b.UseNpgsql(idsServerbuilder.ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
                options.EnableTokenCleanup = true;
            }).AddAspNetIdentity<MembershipUser>()
            .AddProfileService<ProfileService>();

            X509Certificate2 cert = null;
            using (var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine))
            {
                certStore.Open(OpenFlags.ReadOnly);
                var certCollection = certStore.Certificates.Find(
                    X509FindType.FindByThumbprint,
                    "thumbprint",
                    false);

                if (certCollection.Count > 0)
                {
                    cert = certCollection[0];
                }
            }
            if (Environment.IsDevelopment())
            {
                idBuilder.AddDeveloperSigningCredential();
            }
            else
            {
                idBuilder.AddSigningCredential(cert);
            }

            idBuilder.Services.ConfigureExternalCookie(options =>
            {
                options.Cookie.IsEssential = true;
                options.Cookie.SameSite = (SameSiteMode)(-1); 
            });

            idBuilder.Services.ConfigureApplicationCookie(options =>
            {
                options.Cookie.IsEssential = true;
                options.Cookie.SameSite = (SameSiteMode)(-1);
            });

            services.AddMediatR(typeof(Startup));

            RegisterServices(services);
        }

        private void RegisterServices(IServiceCollection services)
        {
            services.AddSingleton<IEventBus, RabbitMQBus>(sp =>
            {
                var scopeFactory = sp.GetRequiredService<IServiceScopeFactory>();
                return new RabbitMQBus(sp.GetService<IMediator>(), scopeFactory);
            });

            services.AddTransient<UserDBContext>();
        }
        
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (Environment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // uncomment if you want to add MVC
            app.UseStaticFiles();
            app.UseRouting();

            app.UseIdentityServer();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapDefaultControllerRoute();
            });
        }
    }

我可以使用 MemoryCacheTicketStore 将 cookie 存储到 SessionStore 中吗?请分享您的想法。

asp.net-core identityserver4 openid-connect iis-10
1个回答
3
投票

一个潜在的问题可能是 IIS 认为 cookie 标头太长。

默认情况下,ASP.NET Core 将 cookie 分成 4Kb 块,如下图所示:

那么,要么尝试减小 cookie 的大小,要么查看 IIS 设置,是否可以增加最大标头长度?

或者,您可以通过设置停止在 cookie 中保存令牌:

options.SaveTokens = false;

现在您当然需要将其存储在其他地方,例如令牌存储中。

我最近还在博客中介绍了如何减小 cookie 大小,同时提高安全性。

通过减少 Cookie 来提高 ASP.NET Core 安全性

© www.soinside.com 2019 - 2024. All rights reserved.