Blazor服务器端-如何使用RevalidatingServerAuthenticationStateProvider继续检查令牌到期?

问题描述

我正在尝试创建一个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);
    }
}

配置服务

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();            
    }

注入的对象:

The injected object

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

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

services.AddScoped<TokenExpiryAuthStateProvider>();
services.AddScoped<ITokenExpiryProvider>(provider => 
        provider.GetrequiredService<TokenExpiryAuthStateProvider>());

然后我将ITokenExpiryProvider注入MainLayout,并订阅AuthenticationStateChanged事件(我可以看到的唯一事件)。刷新间隔后,未触发任何状态更改,并且尚未调用ValidateAuthenticationStateAsync。 我如何开始重新验证过程,为什么AddScoped 不起作用?

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

我仍然想知道为什么我的实现无法正常工作以及为什么从未调用ValidateAuthenticationStateAsync;我必须以某种方式错误注册了服务。

解决方法

在实施自己的RevalidatingServerAuthenticationStateProvider时,在Blazor Server应用程序中遇到了相同的问题。我发现这个问题是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>();
}