ASP.NET 5 Identity 3 users get signed out after some time
I'm, using RC1 bits and external (Google) authentication, no Identity.EntityFramework.
During login, I set 'Remember me' flag.
Logged-in user survives browser restart (I see cookie set to expire in 14 days) and website restart.
But after some time of inactivity (about 15 min), no matter browser/site were restarted or not, refreshing page lead to signing out, logs says:
info: Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationMiddleware:
AuthenticationScheme: Microsoft.AspNet.Identity.Application signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.External signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.TwoFactorUserId signed out.
This looks like "sessions" in previous ASP, but I do not use any sessions here.
This is my local developer machine, no IIS, direct Kestrel connection to 5000 port, so this is not data-protection problem
Why user forced to sign out?
Update: my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
....
var identityBuilder = services
.AddIdentity<User, UserRole>(options =>
{
options.User.AllowedUserNameCharacters = null;
options.Cookies.ApplicationCookie.LoginPath = "/user/login";
options.Cookies.ApplicationCookie.LogoutPath = "/user/logout";
});
identityBuilder.Services
.AddScoped<IUserStore<User>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>())
.AddScoped<IRoleStore<UserRole>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>());
identityBuilder
.AddDefaultTokenProviders();
....
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
....
app.UseIdentity();
app.UseGoogleAuthentication(options =>
{
options.ClientId = Configuration["OAuth:Google:ClientId"];
options.ClientSecret = Configuration["OAuth:Google:Secret"];
});
....
SportCmsDb is DbContext and also implements IUserStore<User>, IUserLoginStore<User>, IUserEmailStore<User>, IRoleStore<UserRole>, IUserClaimStore<User>
Update 2
I enabled detailed (debug) logging and found that when user get signed out - prior to this my IUserStore<User>.FindByIdAsync is called. With real/existing user id, and function returning correct non-null User. Everything seems good. But my loaded-from-db User is "rejected" and forced to sign out. There is not additional log messages that can reveal why/where.
asp.net-core asp.net-identity-3
add a comment |
I'm, using RC1 bits and external (Google) authentication, no Identity.EntityFramework.
During login, I set 'Remember me' flag.
Logged-in user survives browser restart (I see cookie set to expire in 14 days) and website restart.
But after some time of inactivity (about 15 min), no matter browser/site were restarted or not, refreshing page lead to signing out, logs says:
info: Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationMiddleware:
AuthenticationScheme: Microsoft.AspNet.Identity.Application signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.External signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.TwoFactorUserId signed out.
This looks like "sessions" in previous ASP, but I do not use any sessions here.
This is my local developer machine, no IIS, direct Kestrel connection to 5000 port, so this is not data-protection problem
Why user forced to sign out?
Update: my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
....
var identityBuilder = services
.AddIdentity<User, UserRole>(options =>
{
options.User.AllowedUserNameCharacters = null;
options.Cookies.ApplicationCookie.LoginPath = "/user/login";
options.Cookies.ApplicationCookie.LogoutPath = "/user/logout";
});
identityBuilder.Services
.AddScoped<IUserStore<User>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>())
.AddScoped<IRoleStore<UserRole>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>());
identityBuilder
.AddDefaultTokenProviders();
....
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
....
app.UseIdentity();
app.UseGoogleAuthentication(options =>
{
options.ClientId = Configuration["OAuth:Google:ClientId"];
options.ClientSecret = Configuration["OAuth:Google:Secret"];
});
....
SportCmsDb is DbContext and also implements IUserStore<User>, IUserLoginStore<User>, IUserEmailStore<User>, IRoleStore<UserRole>, IUserClaimStore<User>
Update 2
I enabled detailed (debug) logging and found that when user get signed out - prior to this my IUserStore<User>.FindByIdAsync is called. With real/existing user id, and function returning correct non-null User. Everything seems good. But my loaded-from-db User is "rejected" and forced to sign out. There is not additional log messages that can reveal why/where.
asp.net-core asp.net-identity-3
Could you include your call to services.AddIdentity in ConfigureServices, or did you remove that entirely? Are you still usingapp.UseIdentity();in the Startup.Configure method?
– Ron DeFreitas
May 11 '16 at 19:35
Updated my post with parts ofStartup.cs
– Dmitry
May 11 '16 at 21:35
add a comment |
I'm, using RC1 bits and external (Google) authentication, no Identity.EntityFramework.
During login, I set 'Remember me' flag.
Logged-in user survives browser restart (I see cookie set to expire in 14 days) and website restart.
But after some time of inactivity (about 15 min), no matter browser/site were restarted or not, refreshing page lead to signing out, logs says:
info: Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationMiddleware:
AuthenticationScheme: Microsoft.AspNet.Identity.Application signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.External signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.TwoFactorUserId signed out.
This looks like "sessions" in previous ASP, but I do not use any sessions here.
This is my local developer machine, no IIS, direct Kestrel connection to 5000 port, so this is not data-protection problem
Why user forced to sign out?
Update: my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
....
var identityBuilder = services
.AddIdentity<User, UserRole>(options =>
{
options.User.AllowedUserNameCharacters = null;
options.Cookies.ApplicationCookie.LoginPath = "/user/login";
options.Cookies.ApplicationCookie.LogoutPath = "/user/logout";
});
identityBuilder.Services
.AddScoped<IUserStore<User>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>())
.AddScoped<IRoleStore<UserRole>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>());
identityBuilder
.AddDefaultTokenProviders();
....
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
....
app.UseIdentity();
app.UseGoogleAuthentication(options =>
{
options.ClientId = Configuration["OAuth:Google:ClientId"];
options.ClientSecret = Configuration["OAuth:Google:Secret"];
});
....
SportCmsDb is DbContext and also implements IUserStore<User>, IUserLoginStore<User>, IUserEmailStore<User>, IRoleStore<UserRole>, IUserClaimStore<User>
Update 2
I enabled detailed (debug) logging and found that when user get signed out - prior to this my IUserStore<User>.FindByIdAsync is called. With real/existing user id, and function returning correct non-null User. Everything seems good. But my loaded-from-db User is "rejected" and forced to sign out. There is not additional log messages that can reveal why/where.
asp.net-core asp.net-identity-3
I'm, using RC1 bits and external (Google) authentication, no Identity.EntityFramework.
During login, I set 'Remember me' flag.
Logged-in user survives browser restart (I see cookie set to expire in 14 days) and website restart.
But after some time of inactivity (about 15 min), no matter browser/site were restarted or not, refreshing page lead to signing out, logs says:
info: Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationMiddleware:
AuthenticationScheme: Microsoft.AspNet.Identity.Application signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.External signed out.
AuthenticationScheme: Microsoft.AspNet.Identity.TwoFactorUserId signed out.
This looks like "sessions" in previous ASP, but I do not use any sessions here.
This is my local developer machine, no IIS, direct Kestrel connection to 5000 port, so this is not data-protection problem
Why user forced to sign out?
Update: my Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
....
var identityBuilder = services
.AddIdentity<User, UserRole>(options =>
{
options.User.AllowedUserNameCharacters = null;
options.Cookies.ApplicationCookie.LoginPath = "/user/login";
options.Cookies.ApplicationCookie.LogoutPath = "/user/logout";
});
identityBuilder.Services
.AddScoped<IUserStore<User>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>())
.AddScoped<IRoleStore<UserRole>, SportCmsDb>(serviceProvider => serviceProvider.GetService<SportCmsDb>());
identityBuilder
.AddDefaultTokenProviders();
....
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
....
app.UseIdentity();
app.UseGoogleAuthentication(options =>
{
options.ClientId = Configuration["OAuth:Google:ClientId"];
options.ClientSecret = Configuration["OAuth:Google:Secret"];
});
....
SportCmsDb is DbContext and also implements IUserStore<User>, IUserLoginStore<User>, IUserEmailStore<User>, IRoleStore<UserRole>, IUserClaimStore<User>
Update 2
I enabled detailed (debug) logging and found that when user get signed out - prior to this my IUserStore<User>.FindByIdAsync is called. With real/existing user id, and function returning correct non-null User. Everything seems good. But my loaded-from-db User is "rejected" and forced to sign out. There is not additional log messages that can reveal why/where.
asp.net-core asp.net-identity-3
asp.net-core asp.net-identity-3
edited May 23 '17 at 12:34
Community♦
11
11
asked May 11 '16 at 12:30
DmitryDmitry
7,89012945
7,89012945
Could you include your call to services.AddIdentity in ConfigureServices, or did you remove that entirely? Are you still usingapp.UseIdentity();in the Startup.Configure method?
– Ron DeFreitas
May 11 '16 at 19:35
Updated my post with parts ofStartup.cs
– Dmitry
May 11 '16 at 21:35
add a comment |
Could you include your call to services.AddIdentity in ConfigureServices, or did you remove that entirely? Are you still usingapp.UseIdentity();in the Startup.Configure method?
– Ron DeFreitas
May 11 '16 at 19:35
Updated my post with parts ofStartup.cs
– Dmitry
May 11 '16 at 21:35
Could you include your call to services.AddIdentity in ConfigureServices, or did you remove that entirely? Are you still using
app.UseIdentity(); in the Startup.Configure method?– Ron DeFreitas
May 11 '16 at 19:35
Could you include your call to services.AddIdentity in ConfigureServices, or did you remove that entirely? Are you still using
app.UseIdentity(); in the Startup.Configure method?– Ron DeFreitas
May 11 '16 at 19:35
Updated my post with parts of
Startup.cs– Dmitry
May 11 '16 at 21:35
Updated my post with parts of
Startup.cs– Dmitry
May 11 '16 at 21:35
add a comment |
2 Answers
2
active
oldest
votes
Wow, I solved it!
TL;DR
I need to implement IUserSecurityStampStore<User> on my custom UserManager (aka SportCmsDb).
Details
During AddIdentity call (in Startup.cs ConfigureServices method) IdentityOptions are configured with default instance of IdentityCookieOptions. In constructor of IdentityCookieOptions instance of ApplicationCookie (of type CookieAuthenticationOptions) is created with handler CookieAuthenticationEvents.OnValidatePrincipal set to SecurityStampValidator.ValidatePrincipalAsync static method.
During UseIdentity call (in Startup.cs Configure method) CookieAuthenticationMiddleware is configured with IdentityOptions.Cookies.ApplicationCookie options.
CookieAuthenticationHandler (created by CookieAuthenticationMiddleware) in it's HandleAuthenticateAsync method reads ticket from cookie and call Options.Events.ValidatePrincipal handler for validation.
Effectively, SecurityStampValidator.ValidatePrincipalAsync is called. This method checks that enough time has elapsed since cookie was issued (30 min by default) and calls ISecurityStampValidator.validateAsync (lines 81-82).
Default implementation of ISecurityStampValidator is SecurityStampValidator<TUser>. It calls SignInManager<TUser>.ValidateSecurityStampAsync and when null is returned - rejects principal and forces user to sign out (lines 30-40).
SignInManager<TUser> in its ValidateSecurityStampAsync method tries to read security stamp from User and returns null if it can't (if UserManager<User> does not supports this interface) or stamp does not match saved one (in cookie).
My custom UserManager does not implement IUserSecurityStampStore<User>. Bingo.
Hi, I implementedIUserSecurityStampStoreinterface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In theValidateSecurityStampAsyncmethod from the asp.net code I saw that they retrieve a claim with nameSecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.
– Dilyan Dimitrov
May 17 '16 at 13:26
1
You should manually callSetSecurityStampAsynconly when you need user to relogin (say, after changing it's roles/rights from admin page). ClaimSecurityStampClaimTypeis set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value -GetSecurityStampAsyncshould not return null.
– Dmitry
May 17 '16 at 13:34
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but theGetSecurityStampAsync(return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)
– Dilyan Dimitrov
May 17 '16 at 14:33
1
Setoptions.SecurityStampValidationInterval = TimeSpan.FromMinutes(1)inStartup.cswhen configuringIdentityOptions
– Dmitry
May 17 '16 at 15:22
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
|
show 1 more comment
Thank you very much for the previous answers, I worked with this problem today and I resolve with this:
1.- Custom UserStore.cs:
public class UserStore : IUserStore<User>,
IUserPasswordStore<User>,
IUserEmailStore<User>,
IUserRoleStore<User>,
IUserSecurityStampStore<User>
{
//omitted...
public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user.SecurityStamp == null) {
return Task.FromResult("AspNet.Identity.SecurityStamp");
}
return Task.FromResult(user.SecurityStamp);
}
}
2.- In User.cs And DB Table User add SecurityStamp as string.
For TEST change default 30m to 1m in Startup.cs:
services.Configure<SecurityStampValidatorOptions>(options => {
options.ValidationInterval = TimeSpan.FromMinutes(1);
});
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f37162791%2fasp-net-5-identity-3-users-get-signed-out-after-some-time%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Wow, I solved it!
TL;DR
I need to implement IUserSecurityStampStore<User> on my custom UserManager (aka SportCmsDb).
Details
During AddIdentity call (in Startup.cs ConfigureServices method) IdentityOptions are configured with default instance of IdentityCookieOptions. In constructor of IdentityCookieOptions instance of ApplicationCookie (of type CookieAuthenticationOptions) is created with handler CookieAuthenticationEvents.OnValidatePrincipal set to SecurityStampValidator.ValidatePrincipalAsync static method.
During UseIdentity call (in Startup.cs Configure method) CookieAuthenticationMiddleware is configured with IdentityOptions.Cookies.ApplicationCookie options.
CookieAuthenticationHandler (created by CookieAuthenticationMiddleware) in it's HandleAuthenticateAsync method reads ticket from cookie and call Options.Events.ValidatePrincipal handler for validation.
Effectively, SecurityStampValidator.ValidatePrincipalAsync is called. This method checks that enough time has elapsed since cookie was issued (30 min by default) and calls ISecurityStampValidator.validateAsync (lines 81-82).
Default implementation of ISecurityStampValidator is SecurityStampValidator<TUser>. It calls SignInManager<TUser>.ValidateSecurityStampAsync and when null is returned - rejects principal and forces user to sign out (lines 30-40).
SignInManager<TUser> in its ValidateSecurityStampAsync method tries to read security stamp from User and returns null if it can't (if UserManager<User> does not supports this interface) or stamp does not match saved one (in cookie).
My custom UserManager does not implement IUserSecurityStampStore<User>. Bingo.
Hi, I implementedIUserSecurityStampStoreinterface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In theValidateSecurityStampAsyncmethod from the asp.net code I saw that they retrieve a claim with nameSecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.
– Dilyan Dimitrov
May 17 '16 at 13:26
1
You should manually callSetSecurityStampAsynconly when you need user to relogin (say, after changing it's roles/rights from admin page). ClaimSecurityStampClaimTypeis set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value -GetSecurityStampAsyncshould not return null.
– Dmitry
May 17 '16 at 13:34
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but theGetSecurityStampAsync(return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)
– Dilyan Dimitrov
May 17 '16 at 14:33
1
Setoptions.SecurityStampValidationInterval = TimeSpan.FromMinutes(1)inStartup.cswhen configuringIdentityOptions
– Dmitry
May 17 '16 at 15:22
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
|
show 1 more comment
Wow, I solved it!
TL;DR
I need to implement IUserSecurityStampStore<User> on my custom UserManager (aka SportCmsDb).
Details
During AddIdentity call (in Startup.cs ConfigureServices method) IdentityOptions are configured with default instance of IdentityCookieOptions. In constructor of IdentityCookieOptions instance of ApplicationCookie (of type CookieAuthenticationOptions) is created with handler CookieAuthenticationEvents.OnValidatePrincipal set to SecurityStampValidator.ValidatePrincipalAsync static method.
During UseIdentity call (in Startup.cs Configure method) CookieAuthenticationMiddleware is configured with IdentityOptions.Cookies.ApplicationCookie options.
CookieAuthenticationHandler (created by CookieAuthenticationMiddleware) in it's HandleAuthenticateAsync method reads ticket from cookie and call Options.Events.ValidatePrincipal handler for validation.
Effectively, SecurityStampValidator.ValidatePrincipalAsync is called. This method checks that enough time has elapsed since cookie was issued (30 min by default) and calls ISecurityStampValidator.validateAsync (lines 81-82).
Default implementation of ISecurityStampValidator is SecurityStampValidator<TUser>. It calls SignInManager<TUser>.ValidateSecurityStampAsync and when null is returned - rejects principal and forces user to sign out (lines 30-40).
SignInManager<TUser> in its ValidateSecurityStampAsync method tries to read security stamp from User and returns null if it can't (if UserManager<User> does not supports this interface) or stamp does not match saved one (in cookie).
My custom UserManager does not implement IUserSecurityStampStore<User>. Bingo.
Hi, I implementedIUserSecurityStampStoreinterface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In theValidateSecurityStampAsyncmethod from the asp.net code I saw that they retrieve a claim with nameSecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.
– Dilyan Dimitrov
May 17 '16 at 13:26
1
You should manually callSetSecurityStampAsynconly when you need user to relogin (say, after changing it's roles/rights from admin page). ClaimSecurityStampClaimTypeis set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value -GetSecurityStampAsyncshould not return null.
– Dmitry
May 17 '16 at 13:34
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but theGetSecurityStampAsync(return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)
– Dilyan Dimitrov
May 17 '16 at 14:33
1
Setoptions.SecurityStampValidationInterval = TimeSpan.FromMinutes(1)inStartup.cswhen configuringIdentityOptions
– Dmitry
May 17 '16 at 15:22
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
|
show 1 more comment
Wow, I solved it!
TL;DR
I need to implement IUserSecurityStampStore<User> on my custom UserManager (aka SportCmsDb).
Details
During AddIdentity call (in Startup.cs ConfigureServices method) IdentityOptions are configured with default instance of IdentityCookieOptions. In constructor of IdentityCookieOptions instance of ApplicationCookie (of type CookieAuthenticationOptions) is created with handler CookieAuthenticationEvents.OnValidatePrincipal set to SecurityStampValidator.ValidatePrincipalAsync static method.
During UseIdentity call (in Startup.cs Configure method) CookieAuthenticationMiddleware is configured with IdentityOptions.Cookies.ApplicationCookie options.
CookieAuthenticationHandler (created by CookieAuthenticationMiddleware) in it's HandleAuthenticateAsync method reads ticket from cookie and call Options.Events.ValidatePrincipal handler for validation.
Effectively, SecurityStampValidator.ValidatePrincipalAsync is called. This method checks that enough time has elapsed since cookie was issued (30 min by default) and calls ISecurityStampValidator.validateAsync (lines 81-82).
Default implementation of ISecurityStampValidator is SecurityStampValidator<TUser>. It calls SignInManager<TUser>.ValidateSecurityStampAsync and when null is returned - rejects principal and forces user to sign out (lines 30-40).
SignInManager<TUser> in its ValidateSecurityStampAsync method tries to read security stamp from User and returns null if it can't (if UserManager<User> does not supports this interface) or stamp does not match saved one (in cookie).
My custom UserManager does not implement IUserSecurityStampStore<User>. Bingo.
Wow, I solved it!
TL;DR
I need to implement IUserSecurityStampStore<User> on my custom UserManager (aka SportCmsDb).
Details
During AddIdentity call (in Startup.cs ConfigureServices method) IdentityOptions are configured with default instance of IdentityCookieOptions. In constructor of IdentityCookieOptions instance of ApplicationCookie (of type CookieAuthenticationOptions) is created with handler CookieAuthenticationEvents.OnValidatePrincipal set to SecurityStampValidator.ValidatePrincipalAsync static method.
During UseIdentity call (in Startup.cs Configure method) CookieAuthenticationMiddleware is configured with IdentityOptions.Cookies.ApplicationCookie options.
CookieAuthenticationHandler (created by CookieAuthenticationMiddleware) in it's HandleAuthenticateAsync method reads ticket from cookie and call Options.Events.ValidatePrincipal handler for validation.
Effectively, SecurityStampValidator.ValidatePrincipalAsync is called. This method checks that enough time has elapsed since cookie was issued (30 min by default) and calls ISecurityStampValidator.validateAsync (lines 81-82).
Default implementation of ISecurityStampValidator is SecurityStampValidator<TUser>. It calls SignInManager<TUser>.ValidateSecurityStampAsync and when null is returned - rejects principal and forces user to sign out (lines 30-40).
SignInManager<TUser> in its ValidateSecurityStampAsync method tries to read security stamp from User and returns null if it can't (if UserManager<User> does not supports this interface) or stamp does not match saved one (in cookie).
My custom UserManager does not implement IUserSecurityStampStore<User>. Bingo.
answered May 12 '16 at 13:52
DmitryDmitry
7,89012945
7,89012945
Hi, I implementedIUserSecurityStampStoreinterface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In theValidateSecurityStampAsyncmethod from the asp.net code I saw that they retrieve a claim with nameSecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.
– Dilyan Dimitrov
May 17 '16 at 13:26
1
You should manually callSetSecurityStampAsynconly when you need user to relogin (say, after changing it's roles/rights from admin page). ClaimSecurityStampClaimTypeis set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value -GetSecurityStampAsyncshould not return null.
– Dmitry
May 17 '16 at 13:34
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but theGetSecurityStampAsync(return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)
– Dilyan Dimitrov
May 17 '16 at 14:33
1
Setoptions.SecurityStampValidationInterval = TimeSpan.FromMinutes(1)inStartup.cswhen configuringIdentityOptions
– Dmitry
May 17 '16 at 15:22
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
|
show 1 more comment
Hi, I implementedIUserSecurityStampStoreinterface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In theValidateSecurityStampAsyncmethod from the asp.net code I saw that they retrieve a claim with nameSecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.
– Dilyan Dimitrov
May 17 '16 at 13:26
1
You should manually callSetSecurityStampAsynconly when you need user to relogin (say, after changing it's roles/rights from admin page). ClaimSecurityStampClaimTypeis set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value -GetSecurityStampAsyncshould not return null.
– Dmitry
May 17 '16 at 13:34
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but theGetSecurityStampAsync(return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)
– Dilyan Dimitrov
May 17 '16 at 14:33
1
Setoptions.SecurityStampValidationInterval = TimeSpan.FromMinutes(1)inStartup.cswhen configuringIdentityOptions
– Dmitry
May 17 '16 at 15:22
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
Hi, I implemented
IUserSecurityStampStore interface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In the ValidateSecurityStampAsync method from the asp.net code I saw that they retrieve a claim with name SecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.– Dilyan Dimitrov
May 17 '16 at 13:26
Hi, I implemented
IUserSecurityStampStore interface in my custom UserStore and just stored the stamp in the user (SetSecurityStampAsync) and returned it (GetSecurityStampAsync) but the Set method has never been called ? In the ValidateSecurityStampAsync method from the asp.net code I saw that they retrieve a claim with name SecurityStampClaimType? Who is responsible to set that claim ? Me ? In my case I don't have custom UserManager or SignInManager, only the store is custom and there I am only getting the user, no creating users at all.– Dilyan Dimitrov
May 17 '16 at 13:26
1
1
You should manually call
SetSecurityStampAsync only when you need user to relogin (say, after changing it's roles/rights from admin page). Claim SecurityStampClaimType is set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value - GetSecurityStampAsync should not return null.– Dmitry
May 17 '16 at 13:34
You should manually call
SetSecurityStampAsync only when you need user to relogin (say, after changing it's roles/rights from admin page). Claim SecurityStampClaimType is set "internally" (with user id and name claims), don't worry about this. But you should have some initial security stamp value - GetSecurityStampAsync should not return null.– Dmitry
May 17 '16 at 13:34
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but the
GetSecurityStampAsync (return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)– Dilyan Dimitrov
May 17 '16 at 14:33
Okey, I thought everything should be right, but no success :( I put the stamp value in the claims, but the
GetSecurityStampAsync (return the same value I put in the claim) never called.. 30 mins waiting for a test is harsh :)– Dilyan Dimitrov
May 17 '16 at 14:33
1
1
Set
options.SecurityStampValidationInterval = TimeSpan.FromMinutes(1) in Startup.cs when configuring IdentityOptions– Dmitry
May 17 '16 at 15:22
Set
options.SecurityStampValidationInterval = TimeSpan.FromMinutes(1) in Startup.cs when configuring IdentityOptions– Dmitry
May 17 '16 at 15:22
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
Okey.. everything works now! Now I understand the whole idea of this. Thank you so very much for the help, you save my day :)
– Dilyan Dimitrov
May 17 '16 at 15:39
|
show 1 more comment
Thank you very much for the previous answers, I worked with this problem today and I resolve with this:
1.- Custom UserStore.cs:
public class UserStore : IUserStore<User>,
IUserPasswordStore<User>,
IUserEmailStore<User>,
IUserRoleStore<User>,
IUserSecurityStampStore<User>
{
//omitted...
public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user.SecurityStamp == null) {
return Task.FromResult("AspNet.Identity.SecurityStamp");
}
return Task.FromResult(user.SecurityStamp);
}
}
2.- In User.cs And DB Table User add SecurityStamp as string.
For TEST change default 30m to 1m in Startup.cs:
services.Configure<SecurityStampValidatorOptions>(options => {
options.ValidationInterval = TimeSpan.FromMinutes(1);
});
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
add a comment |
Thank you very much for the previous answers, I worked with this problem today and I resolve with this:
1.- Custom UserStore.cs:
public class UserStore : IUserStore<User>,
IUserPasswordStore<User>,
IUserEmailStore<User>,
IUserRoleStore<User>,
IUserSecurityStampStore<User>
{
//omitted...
public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user.SecurityStamp == null) {
return Task.FromResult("AspNet.Identity.SecurityStamp");
}
return Task.FromResult(user.SecurityStamp);
}
}
2.- In User.cs And DB Table User add SecurityStamp as string.
For TEST change default 30m to 1m in Startup.cs:
services.Configure<SecurityStampValidatorOptions>(options => {
options.ValidationInterval = TimeSpan.FromMinutes(1);
});
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
add a comment |
Thank you very much for the previous answers, I worked with this problem today and I resolve with this:
1.- Custom UserStore.cs:
public class UserStore : IUserStore<User>,
IUserPasswordStore<User>,
IUserEmailStore<User>,
IUserRoleStore<User>,
IUserSecurityStampStore<User>
{
//omitted...
public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user.SecurityStamp == null) {
return Task.FromResult("AspNet.Identity.SecurityStamp");
}
return Task.FromResult(user.SecurityStamp);
}
}
2.- In User.cs And DB Table User add SecurityStamp as string.
For TEST change default 30m to 1m in Startup.cs:
services.Configure<SecurityStampValidatorOptions>(options => {
options.ValidationInterval = TimeSpan.FromMinutes(1);
});
Thank you very much for the previous answers, I worked with this problem today and I resolve with this:
1.- Custom UserStore.cs:
public class UserStore : IUserStore<User>,
IUserPasswordStore<User>,
IUserEmailStore<User>,
IUserRoleStore<User>,
IUserSecurityStampStore<User>
{
//omitted...
public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user.SecurityStamp == null) {
return Task.FromResult("AspNet.Identity.SecurityStamp");
}
return Task.FromResult(user.SecurityStamp);
}
}
2.- In User.cs And DB Table User add SecurityStamp as string.
For TEST change default 30m to 1m in Startup.cs:
services.Configure<SecurityStampValidatorOptions>(options => {
options.ValidationInterval = TimeSpan.FromMinutes(1);
});
answered Nov 22 '18 at 1:36
UrielUriel
1213
1213
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
add a comment |
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
This solved my 'logout' problem in ASPNETCORE 2.1. My problem was using a custom user store which didn't implement 'IUserSecurityStampStore' (who knew?!) and thought the fault was with the sliding expiration cookies stuff. The only difference in my code to Uriel's is the 'User user' was 'CustomUser user'.
– Sid James
20 hours ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f37162791%2fasp-net-5-identity-3-users-get-signed-out-after-some-time%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Could you include your call to services.AddIdentity in ConfigureServices, or did you remove that entirely? Are you still using
app.UseIdentity();in the Startup.Configure method?– Ron DeFreitas
May 11 '16 at 19:35
Updated my post with parts of
Startup.cs– Dmitry
May 11 '16 at 21:35