ASP.NET 5 Identity 3 users get signed out after some time












2















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.










share|improve this question

























  • 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
















2















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.










share|improve this question

























  • 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














2












2








2








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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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



















  • 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

















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












2 Answers
2






active

oldest

votes


















6














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.






share|improve this answer
























  • 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





    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






  • 1





    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



















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





share|improve this answer
























  • 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











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


}
});














draft saved

draft discarded


















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









6














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.






share|improve this answer
























  • 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





    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






  • 1





    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
















6














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.






share|improve this answer
























  • 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





    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






  • 1





    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














6












6








6







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.






share|improve this answer













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.







share|improve this answer












share|improve this answer



share|improve this answer










answered May 12 '16 at 13:52









DmitryDmitry

7,89012945




7,89012945













  • 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





    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






  • 1





    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



















  • 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





    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






  • 1





    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

















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













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





share|improve this answer
























  • 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
















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





share|improve this answer
























  • 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














1












1








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





share|improve this answer













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






share|improve this answer












share|improve this answer



share|improve this answer










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



















  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Ottavio Pratesi

Tricia Helfer

15 giugno