Blazor WebAssembly 应用程序每秒执行多次 OIDC 静默登录

Posted

技术标签:

【中文标题】Blazor WebAssembly 应用程序每秒执行多次 OIDC 静默登录【英文标题】:Blazor WebAssembly Application Performs OIDC Silent Sign-in Multiple Times a Second 【发布时间】:2021-05-26 05:18:53 【问题描述】:

我在使用 .NET 5.0.2 Blazor WebAssembly 和 IdentityServer4 的 OIDC 身份验证时遇到了一个非常令人沮丧的问题。在新选项卡中加载页面按预期工作,但当页面发生错误或重新加载选项卡时,应用程序陷入无限静默登录循环,依次向/connect/authorize/.well-known/openid-configuration 发出请求, /connect/token 每秒多次通过隐藏的 iframe。正如问题所暗示的,它仅在用户登录时发生。

OIDC 身份验证配置

builder.Services.AddOidcAuthentication(options => 
                options.ProviderOptions.Authority = "https://localhost:5001/";
                options.ProviderOptions.ClientId = "client-id";
                options.ProviderOptions.DefaultScopes.Add("openid");
                options.ProviderOptions.DefaultScopes.Add("profile");
                options.ProviderOptions.DefaultScopes.Add("roles");
                options.ProviderOptions.PostLogoutRedirectUri = "/";
                options.ProviderOptions.ResponseType = "code";

                options.UserOptions.RoleClaim = "role";
            );

App.razor

<CascadingAuthenticationState>
    <CascadingBlazoredModal>
        <Router AppAssembly="@typeof(Program).Assembly">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                    <Authorizing>
                        <div class="screen-centred auth-spinner">
                            <Spinner />
                        </div>
                    </Authorizing>
                    <NotAuthorized>
                        @if (!context.User.Identity.IsAuthenticated) 
                            <RedirectToLogin />
                         else 
                            <p>You are not authorized to access this resource.</p>
                        
                    </NotAuthorized>
                </AuthorizeRouteView>
            </Found>
            <NotFound>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p>Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>
    </CascadingBlazoredModal>
</CascadingAuthenticationState>

身份服务器配置

public void ConfigureServices(IServiceCollection services) 
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseNpgsql(Configuration.GetConnectionString("IdentityContext")).UseSnakeCaseNamingConvention());

            services.AddIdentity<ApplicationUser, IdentityRole<Guid>>()
                    .AddEntityFrameworkStores<ApplicationDbContext>()
                    .AddDefaultTokenProviders();

            IIdentityServerBuilder? builder = services.AddIdentityServer(options => 
                                                          options.Events.RaiseErrorEvents = true;
                                                          options.Events.RaiseInformationEvents = true;
                                                          options.Events.RaiseFailureEvents = true;
                                                          options.Events.RaiseSuccessEvents = true;

                                                          // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html
                                                          options.EmitStaticAudienceClaim = true;
                                                      )
                                                      .AddInMemoryIdentityResources(Config.IdentityResources)
                                                      .AddInMemoryApiScopes(Config.ApiScopes)
                                                      .AddInMemoryClients(Config.Clients)
                                                      .AddAspNetIdentity<ApplicationUser>();

            builder.AddDeveloperSigningCredential();

            services.AddAuthentication();
        

Image of the Initiatior Chain from Chrome

我已经检查了所有代码,并且问题不是由我对 AuthenticationStateProvider 服务的任何使用引起的,因此我认为这是配置错误的结果。我没有在网上找到有关此问题的任何其他报告,我不确定我的配置错误会导致此问题。

【问题讨论】:

嗨 Garett 我目前正在做一些非常相似的事情(ID4、独立的 WasmPWA 客户端和单独的网关)。我根本没有看到这种行为。我认为我们需要更多地了解代码库。 @BrianParker 感谢您查看 Brian,根据您的评论,我进行了一些测试,发现当我在托管的 Asp.NET 核心之外自行运行客户端时,并没有出现此问题环境。我意识到我仍然有来自服务器上原始项目模板的脚手架身份验证代码,这似乎是导致问题的原因。 【参考方案1】:

在挖掘了所有客户端代码后,我试图找出问题所在,我意识到当 WASM 客户端独立运行而不是在 ASP.NET 服务器上运行时,问题并没有发生。服务器的 Startup.cs 类仍然包含来自个人用户帐户项目模板的代码,这似乎是根本原因。

从 Startup.cs 类中删除注释掉的行后,我无法重现该问题

namespace Server 
    public class Startup 
        public Startup(IConfiguration configuration) 
            Configuration = configuration;
        

        public IConfiguration Configuration  get; 

        public void ConfigureServices(IServiceCollection services) 
            // services.AddDbContext<ApplicationDbContext>(options =>
            //    options.UseSqlServer(
            //        Configuration.GetConnectionString("DefaultConnection")));

            services.AddDatabaseDeveloperPageExceptionFilter();

            // services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
            //     .AddEntityFrameworkStores<ApplicationDbContext>();
            //
            // services.AddIdentityServer()
            //     .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
            //
            // services.AddAuthentication()
            //     .AddIdentityServerJwt();

            //services.AddServerSideBlazor();
            //services.AddBlazoredModal();

            services.AddControllersWithViews();
            services.AddRazorPages();
        

        // 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();
                app.UseWebAssemblyDebugging();
             else 
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            

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

            app.UseRouting();

            // app.UseIdentityServer();
            // app.UseAuthentication();
            // app.UseAuthorization();

            app.UseEndpoints(endpoints => 
                endpoints.MapRazorPages();
                endpoints.MapControllers();
                endpoints.MapFallbackToFile("/index.html");
            );
        
    

【讨论】:

以上是关于Blazor WebAssembly 应用程序每秒执行多次 OIDC 静默登录的主要内容,如果未能解决你的问题,请参考以下文章

「译」 用 Blazor WebAssembly 实现微前端

为 Blazor WebAssembly 中的所有 blazor 页面实例化一个对象?

明晚7点半 | Blazor + WebAssembly开启Web开发新体验

检查 Blazor 应用程序是 WebAssembly 还是服务器?

Blazor正式成为Microsoft官方.NET 和WebAssembly项目

如何正确部署 Blazor WebAssembly(托管)应用程序?