c# - ASP.NET Identity regenerats Identity at each request -


i have asp.net mvc application , i'm using asp.net identity 2. have weird problem. applicationuser.generateuseridentityasync getting called each request browser makes website. i've added trace.writeline , result after removing iis output:

identityconfig.configuration called applicationuser.generateuseridentityasync called url: http://localhost:54294/ applicationuser.generateuseridentityasync called url: http://localhost:54294/content/bootstrap.css applicationuser.generateuseridentityasync called url: http://localhost:54294/scripts/modernizr-2.8.3.js applicationuser.generateuseridentityasync called url: http://localhost:54294/content/site.css applicationuser.generateuseridentityasync called url: http://localhost:54294/scripts/jquery-2.1.3.js applicationuser.generateuseridentityasync called url: http://localhost:54294/scripts/bootstrap.js applicationuser.generateuseridentityasync called url: http://localhost:54294/scripts/respond.js applicationuser.generateuseridentityasync called url: http://localhost:54294/scripts/script.js applicationuser.generateuseridentityasync called url: http://localhost:54294/glimpse.axd?n=glimpse_client&hash=8913cd7e applicationuser.generateuseridentityasync called url: http://localhost:54294/glimpse.axd?n=glimpse_metadata&hash=8913cd7e&callback=glimpse.data.initmetadata applicationuser.generateuseridentityasync called url: http://localhost:54294/glimpse.axd?n=glimpse_request&requestid=6171c2b0-b6e5-4495-b495-4fdaddbe6e8f&hash=8913cd7e&callback=glimpse.data.initdata applicationuser.generateuseridentityasync called url: http://localhost:54294/glimpse.axd?n=glimpse_sprite&hash=8913cd7e applicationuser.generateuseridentityasync called url: http://localhost:54294/__browserlink/requestdata/38254292a54f4595ad26158540adbb6a?version=2 

while if run default mvc application created template, i'm getting this:

identityconfig.configuration called 

and if login, it'll call applicationuser.generateuseridentityasync.

i've looked everywhere thought might didn't find result. i'm using (if helps)

structuremap 3 elmah glimpse asp.net mvc 5 ef6 asp.net identity 2 

additional info

i'm adding users directly database without using usermanage. i'm not sure if makes problems identity or not.


update

i've dropped database , didn't happen anymore. happening?

update 2

it happened in google chrome (i monitor sql connections using glimpse) , after removing stored cookies, didn't happen. can logging in in other browsers cause problem?

update 3

also log off - log in seems solve problem temporary.

i had same problem , after digging in source code , detective work found solution. problem inside securitystampvalidator, used default onvalidateidentity handler. see source code here. interesting part:

var issuedutc = context.properties.issuedutc;  // validate if enough time has elapsed var validate = (issuedutc == null); if (issuedutc != null) {     var timeelapsed = currentutc.subtract(issuedutc.value);     validate = timeelapsed > validateinterval; } 

this part runs each request , if validate true, getuseridcallback , regenerateidentitycallback (visible in trace output) called. problem here issuedutc date when cookie created, validate true when validateinterval has passed. explains weird behavior experiencing. if validateinterval 10 minutes, validation logic run each request coming in 10 minutes , more after cookie created (application deployed, cookies cleared, cookie reset when logging out , in again).

securitystampvalidator should make decisions whether validate or not, basing on previous validation date (or issued date when it's first check), it's not doing so. make issuedutc date move forward there 3 possible solutions:

  • reset cookie each validateinterval, means singout , signin. similar solution here. seems costly operation, if validateinterval set couple of minutes.
  • take advantage of cookieauthenticationoptions.slidingexpiration logic have cookie re-issued automatically. explained in this post.

if slidingexpiration set true cookie re-issued on request half way through expiretimespan. example, if user logged in , made second request 16 minutes later cookie re-issued 30 minutes. if user logged in , made second request 31 minutes later user prompted log in.

in case (intranet application) users being logged out after 30 minutes of inactivity unacceptable. need have default expiretimespan, 14 days. option here implement kind of ajax polling extend cookie life. sounds lot of effort accomplish simple scenario.

  • the last option, chose use modify securitystampvalidator implementation have sliding validation approach. example code below. remember replace securitystampvalidator slidingsecuritystampvalidator in startup.auth.cs. added identityvalidationdates dictionary original implementation store validation dates each user , i'm using when checking if validation needed.

    public static class slidingsecuritystampvalidator {     private static readonly idictionary<string, datetimeoffset> identityvalidationdates = new dictionary<string, datetimeoffset>();      public static func<cookievalidateidentitycontext, task> onvalidateidentity<tmanager, tuser, tkey>(         timespan validateinterval, func<tmanager, tuser, task<claimsidentity>> regenerateidentitycallback,         func<claimsidentity, tkey> getuseridcallback)         tmanager : usermanager<tuser, tkey>         tuser : class, iuser<tkey>         tkey : iequatable<tkey>     {         if (getuseridcallback == null)         {             throw new argumentnullexception(nameof(getuseridcallback));         }          return async context =>         {             var currentutc = datetimeoffset.utcnow;             if (context.options != null && context.options.systemclock != null)             {                 currentutc = context.options.systemclock.utcnow;             }             var issuedutc = context.properties.issuedutc;              // validate if enough time has elapsed             var validate = issuedutc == null;             if (issuedutc != null)             {                 datetimeoffset lastvalidateutc;                 if (identityvalidationdates.trygetvalue(context.identity.name, out lastvalidateutc))                 {                     issuedutc = lastvalidateutc;                 }                  var timeelapsed = currentutc.subtract(issuedutc.value);                 validate = timeelapsed > validateinterval;             }              if (validate)             {                 identityvalidationdates[context.identity.name] = currentutc;                  var manager = context.owincontext.getusermanager<tmanager>();                 var userid = getuseridcallback(context.identity);                 if (manager != null && userid != null)                 {                     var user = await manager.findbyidasync(userid);                     var reject = true;                      // refresh identity if stamp matches, otherwise reject                     if (user != null && manager.supportsusersecuritystamp)                     {                         var securitystamp = context.identity.findfirstvalue(constants.defaultsecuritystampclaimtype);                         if (securitystamp == await manager.getsecuritystampasync(userid))                         {                             reject = false;                             // regenerate fresh claims if possible , resign in                             if (regenerateidentitycallback != null)                             {                                 var identity = await regenerateidentitycallback.invoke(manager, user);                                 if (identity != null)                                 {                                     // fix regression value not updated                                     // setting null refreshed cookie middleware                                     context.properties.issuedutc = null;                                     context.properties.expiresutc = null;                                     context.owincontext.authentication.signin(context.properties, identity);                                 }                             }                         }                     }                      if (reject)                     {                         context.rejectidentity();                         context.owincontext.authentication.signout(context.options.authenticationtype);                     }                 }             }         };     } } 

Comments

Popular posts from this blog

cakephp - simple blog with croogo -

How to group boxplot outliers in gnuplot -

bash - Performing variable substitution in a string -