Angular Oidc客户端js:静默访问令牌续订中断,因为身份服务器身份验证cookie滑动过期不';行不通

Angular Oidc客户端js:静默访问令牌续订中断,因为身份服务器身份验证cookie滑动过期不';行不通,angular,identityserver4,openid-connect,oidc-client-js,Angular,Identityserver4,Openid Connect,Oidc Client Js,我正在使用angular SPA,它通过使用和实现身份验证 在静默访问令牌续订级别,某些内容不起作用。预期的行为是访问令牌的自动续订,由于调用/connect/authorize端点的iframe,这种情况在引擎盖下发生。此调用随HTTP请求一起发送identity server身份验证cookie,这样identity server就知道用户会话仍然有效,并且能够发出新的访问令牌,而不需要用户以交互方式再次登录。到目前为止,我确信我的理解是正确的 这里是棘手的部分:我的期望是identity

我正在使用angular SPA,它通过使用和实现身份验证

在静默访问令牌续订级别,某些内容不起作用。预期的行为是访问令牌的自动续订,由于调用
/connect/authorize
端点的iframe,这种情况在引擎盖下发生。此调用随HTTP请求一起发送identity server身份验证cookie,这样identity server就知道用户会话仍然有效,并且能够发出新的访问令牌,而不需要用户以交互方式再次登录。到目前为止,我确信我的理解是正确的

这里是棘手的部分:我的期望是identity server身份验证cookie应该有一个滑动过期,以便每次调用
/connect/authorize
端点时,其过期日期都会及时向前移动。换句话说,我希望在用户第一次登录后,不需要用户进行其他交互登录,,因为每次静默续订iframe需要新的访问令牌时,用户会话过期日期都会自动向前移动

为了获得这种行为,我在identity server级别设置了以下配置

这是客户端配置(请注意,访问令牌生存期为2分钟=120秒):

这是
ConfigureServices
,我在这里添加了所有identity server配置。请注意,cookie生存期设置为15分钟,并且需要cookie滑动到期:

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<RequestLoggingOptions>(o =>
            {
                o.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
                {
                    diagnosticContext.Set("RemoteIpAddress", httpContext.Connection.RemoteIpAddress.MapToIPv4());
                };
            });

            services.AddControllersWithViews();

            var migrationsAssembly = GetRunningAssemblyName();
            var connectionString = this.Configuration.GetConnectionString(IdentityServerDatabaseConnectionString);

            var identityServerBuilder = services.AddIdentityServer(options =>
            {
                options.Authentication.CookieLifetime = TimeSpan.FromMinutes(15);
                options.Authentication.CookieSlidingExpiration = true;
            })
            .AddTestUsers(TestData.Users)
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = dbContextBuilder =>
                    dbContextBuilder.UseSqlServer(
                        connectionString,
                        sqlServerOptionsBuilder => sqlServerOptionsBuilder.MigrationsAssembly(migrationsAssembly)
                    );
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = dbContextBuilder =>
                    dbContextBuilder.UseSqlServer(
                        connectionString,
                        sqlServerOptionsBuilder => sqlServerOptionsBuilder.MigrationsAssembly(migrationsAssembly)
                    );
            });

            services.AddAuthentication(x => x.DefaultAuthenticateScheme = IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme);

            identityServerBuilder.AddDeveloperSigningCredential();
        }
public void配置服务(IServiceCollection服务)
{
服务配置(o=>
{
o、 EnricDiagnosticContext=(diagnosticContext,httpContext)=>
{
diagnosticContext.Set(“RemoteIpAddress”,httpContext.Connection.RemoteIpAddress.MapToIPv4());
};
});
services.AddControllersWithViews();
var migrationassembly=GetRunningAssemblyName();
var connectionString=this.Configuration.GetConnectionString(IdentityServerDatabaseConnectionString);
var identityServerBuilder=services.AddIdentityServer(选项=>
{
options.Authentication.CookieLifetime=TimeSpan.FromMinutes(15);
options.Authentication.CookieSlidingExpiration=true;
})
.AddTestUsers(TestData.Users)
.AddConfigurationStore(选项=>
{
options.ConfigureDbContext=dbContextBuilder=>
dbContextBuilder.UseSqlServer(
连接字符串,
sqlServerOptionsBuilder=>sqlServerOptionsBuilder.MigrationsAssembly(MigrationsAssembly)
);
})
.addStore(选项=>
{
options.ConfigureDbContext=dbContextBuilder=>
dbContextBuilder.UseSqlServer(
连接字符串,
sqlServerOptionsBuilder=>sqlServerOptionsBuilder.MigrationsAssembly(MigrationsAssembly)
);
});
services.AddAuthentication(x=>x.DefaultAuthenticationScheme=IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme);
identityServerBuilder.AddDeveloperSigningCredential();
}
我已经添加了对
services.AddAuthentication的调用(x=>x.DefaultAuthenticationScheme=IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme)阅读后。根据我的理解,此调用是多余的,因为对
服务.AddIdentityServer
的调用应该已经使用常量
IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme
作为身份验证方案名称,将cookie身份验证设置为默认身份验证方案

通过使用此identity server配置,silen访问令牌续订不会以我期望的方式工作

访问令牌以静默方式续订14次,然后第十五次续订访问令牌的尝试失败,并显示消息
SilentRenewService.\u令牌过期:登录错误\u必需

这基本上意味着身份验证cookie滑动过期不起作用,因为我的身份验证cookie有15分钟的生命周期,我的SPA客户端的访问令牌有2分钟的生命周期,而oidc客户端js库每分钟执行一次静默刷新周期(访问令牌在到期前60秒续订,因此,通过我的设置,静默续订每分钟完成一次)。在第十五次尝试续订访问令牌时,身份验证cookie最终过期,并且identity server授权终结点返回对
https://localhost:4200/assets/silent-callback.html
静态页面

以下是我的控制台日志(请注意,silen renew已按预期工作了14次):

以下是identity server编写的服务器端日志,用于确认用户会话在第十五次尝试时已过期:

成功尝试续订访问令牌期间调用
/connect/authorize
端点时,这些是identity server返回的响应头(续订访问令牌的前14次尝试之一)。请注意,有一个响应标头,它为
idsrv
cookie设置了一个新值:

这些是identity server在
/connect/authorize
端点
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<RequestLoggingOptions>(o =>
            {
                o.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
                {
                    diagnosticContext.Set("RemoteIpAddress", httpContext.Connection.RemoteIpAddress.MapToIPv4());
                };
            });

            services.AddControllersWithViews();

            var migrationsAssembly = GetRunningAssemblyName();
            var connectionString = this.Configuration.GetConnectionString(IdentityServerDatabaseConnectionString);

            var identityServerBuilder = services.AddIdentityServer(options =>
            {
                options.Authentication.CookieLifetime = TimeSpan.FromMinutes(15);
                options.Authentication.CookieSlidingExpiration = true;
            })
            .AddTestUsers(TestData.Users)
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = dbContextBuilder =>
                    dbContextBuilder.UseSqlServer(
                        connectionString,
                        sqlServerOptionsBuilder => sqlServerOptionsBuilder.MigrationsAssembly(migrationsAssembly)
                    );
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = dbContextBuilder =>
                    dbContextBuilder.UseSqlServer(
                        connectionString,
                        sqlServerOptionsBuilder => sqlServerOptionsBuilder.MigrationsAssembly(migrationsAssembly)
                    );
            });

            services.AddAuthentication(x => x.DefaultAuthenticateScheme = IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme);

            identityServerBuilder.AddDeveloperSigningCredential();
        }
public void ConfigureServices(IServiceCollection services)
    {
        services.AddHealthChecks();

        services.AddControllersWithViews();

        services.AddCustomOptions(Configuration);

        services.AddCustomDbContext(Configuration)
            .ResolveDependencies();

        services.AddIdentityServer(options =>
                {
                    options.Authentication.CookieLifetime = AccountOptions.RememberMeLoginDuration;
                    options.Events.RaiseSuccessEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseErrorEvents = true;
                })
            .AddProfileService<ProfileService>()
            .AddSigningCertificate(Configuration)
            .AddInMemoryClients(Configuration.GetSection("IdentityServer:Clients"))
            .AddInMemoryIdentityResources(Resources.GetIdentityResources())
            .AddInMemoryApiResources(Resources.GetApis());

        var externalProviders = Configuration.GetSection(nameof(ApplicationOptions.ExternalProviders))
            .Get<ExternalProvidersOptions>();

        services.AddWindowsIdentityProvider(externalProviders.UseWindows);

        services.AddLocalization(options => options.ResourcesPath = Constants.Resources);

        services.AddMvc()
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .AddDataAnnotationsLocalization();

        services.AddMvcCore()
            .AddCustomCors();
    }
{
    "Enabled": true,
    "ClientId": "dashboard",
    "ClientName": "Web Client",
    "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ],
    "AllowedGrantTypes": [ "implicit", "authorization_code" ],
    "AllowedScopes": [ "openid", "email", "profile", "role" ],
    "AllowOfflineAccess": true,
    "AllowAccessTokensViaBrowser": true,
    "AllowedCorsOrigins": [
      "http://localhost:7004"
    ],
    "RedirectUris": [
      "http://localhost:7004/callback",
      "http://localhost:7004/refreshtoken"
    ],
    "PostLogoutRedirectUris": [
      "http://localhost:7004"
    ],
    "AccessTokenLifetime": 3600,
    "RequireConsent": false
  }