ASP.NET Identity Core - 角色相关查询过多

3

我的项目使用基于角色的授权,它有超过100个角色。我注意到在每个操作之前,服务器会单独查询每个用户角色及其声明。这意味着在每个操作之前进行200多次查询。即使是空控制器也会这样做,所以我认为这是ASP.NET身份核心功能。是否有任何优化的方法呢?

提前感谢您的帮助。

ASP.NET Core web server output (one out of many role queries):

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[@__role_Id_0='390'], CommandType='Text', CommandTimeout='30']
      SELECT [rc].[ClaimType], [rc].[ClaimValue]
      FROM [AspNetRoleClaims] AS [rc]
      WHERE [rc].[RoleId] = @__role_Id_0
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[@__normalizedName_0='100' (Size = 256)], CommandType='Text', CommandTimeout='30']
      SELECT TOP(1) [r].[Id], [r].[ConcurrencyStamp], [r].[Name], [r].[NormalizedName]
      FROM [AspNetRoles] AS [r]
      WHERE [r].[NormalizedName] = @__normalizedName_0

我的 Startup.cs 类:

    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.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies 
                // is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddRouting(options => options.LowercaseUrls = true);
            services.AddDistributedMemoryCache();
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromDays(1);
                options.Cookie.IsEssential = true;
            });

            services.AddDbContext<AppDbContext>(options =>
                options
                    .EnableSensitiveDataLogging()
                    .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), x =>
                    {
                        x.UseRowNumberForPaging();
                        x.UseNetTopologySuite();
                    }));

            services.Configure<WebEncoderOptions>(options => 
            {
                options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All);
            });

            services.Configure<AppConfiguration>(
                Configuration.GetSection("AppConfiguration"));

            services.AddIdentity<User, UserRole>()
                .AddEntityFrameworkStores<AppDbContext>()
                .AddDefaultTokenProviders();

            services.Configure<IdentityOptions>(options =>
            {
                // Password settings
                options.Password.RequireDigit = true;
                options.Password.RequiredLength = 8;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireUppercase = true;
                options.Password.RequireLowercase = false;
                options.Password.RequiredUniqueChars = 6;

                // Lockout settings
                options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
                options.Lockout.MaxFailedAccessAttempts = 10;
                options.Lockout.AllowedForNewUsers = true;

                // User settings
                options.User.RequireUniqueEmail = true;
            });

            services.Configure<SecurityStampValidatorOptions>(options =>
            {
                // enables immediate logout, after updating the users stat.
                options.ValidationInterval = TimeSpan.Zero;
            });

            services.ConfigureApplicationCookie(options =>
            {
                // Cookie settings
                options.Cookie.HttpOnly = true;
                options.Cookie.Expiration = TimeSpan.FromDays(150);
                // If the LoginPath isn't set, ASP.NET Core defaults 
                // the path to /Account/Login.
                options.LoginPath = "/Account/Login";
                // If the AccessDeniedPath isn't set, ASP.NET Core defaults 
                // the path to /Account/AccessDenied.
                options.AccessDeniedPath = "/Account/AccessDenied";
                options.SlidingExpiration = true;
            });

            // Add application services.
            services.AddScoped<IEmailSenderService, EmailSenderService>();
            services.AddScoped<IUploaderService, UploaderService>();
            services.AddScoped<IPdfService, PdfService>();
            services.AddScoped<ICurrencyRateService, CurrencyRateService>();
            services.AddScoped<IViewRenderService, ViewRenderService>();
            services.AddScoped<IUserCultureInfoService, UserCultureInfoService>();
            services.AddScoped<IUserService, UserService>();
            services.AddHostedService<QueuedHostedService>();
            services.AddSingleton<IBackgroundTaskQueue, BackgroundTaskQueue>();

            services
                .AddMvc(options =>
                {
                    options.EnableEndpointRouting = false;

                    options
                        .RegisterDateTimeProvider(services)
                        .ModelMetadataDetailsProviders
                        .Add(new BindingSourceMetadataProvider(typeof(ListFilterViewModel), BindingSource.ModelBinding));
                })
                .AddSessionStateTempDataProvider()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
                // app.UseMiddleware<StackifyMiddleware.RequestTracerMiddleware>();
            }
            else
            {
#if DEBUG
                app.UseDeveloperExceptionPage();
#else
                app.UseExceptionHandler("/Default/Error");
#endif

                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseSession();
            app.UseCookiePolicy();
            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapAreaRoute(
                    name: "Hubs",
                    areaName:"Hubs",
                    template: "Hubs/{controller=CompanyAddresses}/{action=Index}/{id?}");

                routes.MapRoute(
                    name: "areas",
                    template: "{area:exists}/{controller=Default}/{action=Index}/{id?}"
                );

                routes.MapRoute(
                    name: "default",
                    template: "{controller=Default}/{action=Index}/{id?}");
            });
        }
    }

这是MVC吗?你正在使用哪种身份验证技术? - Marius Steinbach
是的,这是一个MVC项目。我正在使用Identity身份验证: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-3.1&tabs=visual-studio - Marius Lukošiūnas
你能否更新你的问题并提供你的StartUp.cs类? - Marius Steinbach
当然,没问题。已完成。 - Marius Lukošiūnas
一切似乎都在它的位置上。你正在使用UserManager和RoleManager吗? - Marius Steinbach
是的,我已经找到了一个问题,但还是谢谢你关心! - Marius Lukošiūnas
1个回答

0

我已经找到了导致这种奇怪行为的原因。它是我Startup.cs类中的这个代码段:

services.Configure<SecurityStampValidatorOptions>(options =>
{
    // enables immediate logout, after updating the users stat.
    options.ValidationInterval = TimeSpan.Zero;
});

移除它解决了我的问题。我一直在使用这个方法通过更新用户的安全标记来强制注销用户,就像这里描述的那样:如何在ASP.NET Core Identity中注销其他用户

看来我需要寻找其他的强制注销解决方案,但我很高兴现在请求不再生成数百个SQL查询。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接