Blazor 服务器端 - 如何使用 RevalidatingServerAuthenticationStateProvider 持续检查令牌过期情况?

Mat*_*way 6 blazor blazor-server-side asp.net-blazor

我正在尝试创建 RevalidatingServerAuthenticationStateProvider 来检查 ClaimsPrincipal 是否已过期。

我已经创建了它的实现(TokenExpiryAuthStateProvider)并将其注册到ConfigureServices 中,但构造函数从未被调用,ValidateAuthenticationStateAsync 也未被调用。(我也尝试了实现工厂来注册它,结果相同)

我将 AuthStateProvider 注入到 MainLayout 中以查看注入的内容,但它仍在注入 ServerAuthenticationStateProvider。我究竟做错了什么?

我的实现从未被调用:

public class TokenExpiryAuthStateProvider : RevalidatingServerAuthenticationStateProvider
{
    protected override TimeSpan RevalidationInterval => TimeSpan.FromSeconds(10);

    public TokenExpiryAuthStateProvider(ILoggerFactory logger) : base(logger)
    {

    }

    protected override Task<bool> ValidateAuthenticationStateAsync(AuthenticationState authenticationState, CancellationToken cancellationToken)
    {
        DateTime expiry = authenticationState.User.GetExpiryDate();

        if (expiry < DateTime.UtcNow)
            return Task.FromResult(false);
        else
            return Task.FromResult(true);
    }
}
Run Code Online (Sandbox Code Playgroud)

配置服务

public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<HttpClientFactory>();

        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
        services.ConfigureApplicationCookie(options =>
        {
            options.Cookie.HttpOnly = true;
            options.SlidingExpiration = true;
            options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
        });

        services.AddScoped<AuthenticationStateProvider, TokenExpiryAuthStateProvider>();

        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddHttpContextAccessor();

        services.AddCsla().WithBlazorServerSupport();            
    }
Run Code Online (Sandbox Code Playgroud)

注入的对象:

注入的对象

更新: 之前应该提到过这一点...我目前正在开发一个服务器端项目,但布局位于共享 ui 库中。因此,@enet 提出的建议不适合,因为RevalidatingServerAuthenticationStateProvider在共享项目中不可用,因此 TokenExpiryAuthStateProvider 仅在服务器项目中。

尽管如此,根据 enet 的建议,我声明了一个接口并更新了ConfigureServices,以便我可以将其注入到我的共享布局中进行尝试:

services.AddScoped<TokenExpiryAuthStateProvider>();
services.AddScoped<ITokenExpiryProvider>(provider => 
        provider.GetRequiredService<TokenExpiryAuthStateProvider>());
Run Code Online (Sandbox Code Playgroud)

然后,我将 ITokenExpiryProvider 注入到 MainLayout,并订阅 AuthenticationStateChanged 事件(我能看到的唯一事件)。在刷新间隔之后,不会触发任何状态更改,也不会调用 ValidateAuthenticationStateAsync。如何启动重新验证过程以及为什么 AddScoped<AuthenticationStateProvider, TokenExpiryAuthStateProvider> 不起作用?

我认为对于我的简单用例,创建一个注入 AuthenticationStateProvider 的计时器类会更容易;然后,此类封装了对身份验证状态的定期检查,并在会话到期时引发一个事件。(这就是我期望 RevalidatingServerAuthenticationStateProvider 工作的方式,每当 RefreshInterval 过去时检查 ValidateAuthenticationStateAsync

我仍然想知道为什么我的实现不起作用以及为什么 ValidateAuthenticationStateAsync 从未被调用;我一定是错误地注册了该服务。

mkc*_*ler 5

在实现我自己的RevalidatingServerAuthenticationStateProvider. 我发现这个问题是如何在Startup.cs.

通过调用services.AddRazorPages()services.AddServerSideBlazor()在设置身份验证提供程序之前,我纠正了该问题,现在我的ValidationAuthenticationStateAsync()方法在指定的RevalidationInterval.

以下是我的示例ConfigureServices(...)中该方法的缩写版本:Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    // These two need to be called before adding authentication
    services.AddRazorPages();
    services.AddServerSideBlazor();

    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect();

    // This needs to be setup after setting up Blazor
    services.AddScoped<AuthenticationStateProvider, CustomRevalidatingAuthenticationStateProvider>();
}
Run Code Online (Sandbox Code Playgroud)