我正在使用一个使用身份服务器4和oidc客户端js实现身份验证的角SPA。
在静默访问令牌更新级别上,某些内容无法工作。预期的行为是访问令牌的自动更新,由于调用/connect/authorize端点的iframe,访问令牌在外壳下发生。此调用将身份服务器身份验证cookie与HTTP请求一起发送,这样身份服务器就知道用户会话仍然是有效的,并且能够发出新的访问令牌,而不需要用户再次交互登录。到目前为止,我确信我的理解是好的。
下面是棘手的部分:我的期望是身份服务器身份验证cookie应该有一个滑动过期,这样每次调用/connect/authorize端点时,它的过期日期都会提前。换句话说,我期望在用户第一次签署之后,用户不需要其他交互登录,因为用户会话过期日期是,每次沉默的更新iframe需要一个新的访问令牌时,都会自动向前移动。
为了获得这种行为,我在身份服务器级别设置了以下配置。
这是客户端配置(请注意,访问令牌生存期为2分= 120秒):
new Client
{
ClientId = "web-client",
ClientName = "SPA web client",
AllowedGrantTypes = GrantTypes.Code,
RequireClientSecret = false,
RequirePkce = true,
RequireConsent = false,
AccessTokenLifetime = 120,
RedirectUris = { "https://localhost:4200/assets/signin-callback.html", "https://localhost:4200/assets/silent-callback.html" },
PostLogoutRedirectUris = { "https://localhost:4200/signout-callback" },
AllowedCorsOrigins = { "https://localhost:4200" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"dataset",
"exercise",
"user-permissions"
}
}这是ConfigureServices,我在这里添加了所有的身份服务器配置。请注意,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();
}我在阅读了services.AddAuthentication(x => x.DefaultAuthenticateScheme = IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme);之后添加了对这个github问题的调用。根据我的理解,这个调用是多余的,因为对services.AddIdentityServer的调用应该已经将cookie身份验证设置为默认的身份验证方案,方法是使用常量IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme作为身份验证方案名。
通过使用此身份服务器配置,silen更新会使而不是按照我预期的方式工作。
访问令牌被静默地更新了14次,然后第15次尝试更新访问令牌的尝试在消息SilentRenewService._tokenExpiring: Error from signinSilent: login_required中失败。
这基本上意味着身份验证cookie滑动过期不起作用,因为我的身份验证cookie有15分钟的生存期,SPA客户端的访问令牌有2分钟的生存期,而oidc客户端js库每分钟执行一次无声刷新周期(访问令牌在到期前60秒被更新,因此对于我的设置,每分钟都进行无声更新)。在第十五次尝试更新访问令牌时,身份验证cookie最终过期,身份服务器授权端点向https://localhost:4200/assets/silent-callback.html静态页面返回一个错误响应。
这些是我的控制台日志(请注意,沉默更新14次按预期工作):

这些是标识服务器编写的服务器端日志,它确认用户会话在第十五次尝试时过期:

这些是标识服务器在/connect/authorize成功尝试更新访问令牌时调用端点时返回的响应标头(这是更新访问令牌的最初14次尝试之一)。请注意,有一个响应头,它为idsrv cookie设置了一个新值:

这些是标识服务器在试图更新访问令牌/connect/authorize (第十五次尝试更新访问令牌)期间调用端点时返回的响应标头。请注意,idsrv.session cookie是无效的,因为它的过期日期设置为2019年的前一个日期:

我是否遗漏了沉默访问令牌更新与身份验证cookie滑动过期之间的关系?
这是预期的行为吗?
是否有一种方法可以使静默访问令牌更新工作而不需要新的用户登录交互?
更新2020年9月16日
我终于解决了这个问题。
修复方法是将IdentityServer4.EntityFramework nuget包更新为最新的可用版本(截至今天的4.1.0)。
所有细节都被报道为在我自己的关于oidc-client-js github存储库的github问题中。
总之,cookie滑动过期的奇怪行为的根本原因是这个身份服务器错误,由IdentityServer4.EntityFramework nuget包的4.1.0版本修复,如发布说明中所指出的那样。
发布于 2020-09-15 13:46:30
这是我在你的请求上的配置
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();
}此外,follwing是应用程序设置中的客户端配置:
{
"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
}https://stackoverflow.com/questions/63901667
复制相似问题