消息:ID4243:无法创建SecurityToken.在令牌缓存中找不到令牌,并且在上下文中未找到cookie

 淘气小顽童刘 发布于 2023-02-09 19:04

我们在生产环境中得到与此线程完全相同的错误.[ WIF安全令牌缓存

有人解决了这个错误吗?消息:ID4243:无法创建SecurityToken.在令牌缓存中找不到令牌,并且在上下文中未找到cookie.

以下是有关我们设置的一些信息:

•我们在.NET Framework 4.5.1中使用内置Windows Identity Framework

•问题几乎总是与从RelyingParty#X更改为RelyingParty #Y相关联(例如,当用户点击RP#Y他已经签名而没有要求时) - 当他在此事件后再次登录时,他被带到了他要求的页面,在RP#Y内

•我们正在使用e.SessionToken.IsReferenceMode = true; //在服务器上缓存,以获得更小的cookie

•通过使用IsReferenceMode = true,我们的FedAuth cookie存储一个指向实际令牌的"指针",该指针存储在我们的数据库中

•我们使用自己的DatabaseSecurityTokenCache,它覆盖了SessionSecurityTokenCache中的函数.通过使用DatabaseSecurityTokenCache和IsSessionMode = true,我们对服务器场友好(但我们也保证在所有登录会话中都在同一服务器内)所以如果由于某种原因应用程序池死了,我们'能够通过DatabaseSecurityTokenCache从数据库中获取令牌.我已经通过在会话中间完全杀死IIS来验证这一点(使用"net stop WAS"并使用"net start W3SVC"重新启动它,我们仍然可以从DatabaseSecurityTokenCache获取令牌).我也试过通过简单地使用开箱即用的SessionSecurityTokenCache来做同样的事情,并且会分别失败(如预期的那样)

•默认令牌生存期为20分钟(但如果用户可以将其更改为40或60分钟) - 这只会在用户下次登录时生效(并且90%的用户只使用默认令牌20)分钟寿命)

•我们使用证书(在所有服务器上都相同)来加密FedAuth cookie,而不是机器密钥(如果使用服务器场,使用不同的机器密钥,那将是灾难性的)

•因此所有服务器都可以解密从其他服务器加密的cookie.

•我们在RelyingParty4和RelyingParty5(两个不同的依赖方)中有一个倒计时的javascript,用作"超时脚本",以防用户无人看管他的计算机......当令牌即将退出时,他将退出到期 - (减去)30秒(例如20分钟 - 30秒= 19,5分钟),空闲时间.这是保护我们非常敏感的银行信息,因此当用户回到他的机器时,他将需要再次登录.例如,我们也在使用滑动会话([ http://www.cloudidentity.com/blog/2013/05/08/sliding-sessions-for-wif-4-5/]),当我们滑动时,客户端的javascript也会更新,以匹配令牌的长度减去30秒.这30秒用于确保注销时会话仍处于活动状态,因此它比令牌/会话的生命周期短一点.如果满足这个条件,我们目前正在滑动:总寿命/ 2 ....例如20/2

•如果用户正在进行任何活动(即他正在四处走动,做一些工作),我们只会滑动.如上例所示,我们在minute10 +中滑动(如果令牌寿命为20min)

•我们多次调试问题,这是我们得到的WIF错误:异常:System.IdentityModel.Tokens.SecurityTokenException消息:ID4243:无法创建SecurityToken.在令牌缓存中找不到令牌,并且在上下文中未找到cookie.源:Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader,SecurityTokenResolver tokenResolver)中的Microsoft.IdentityModel,位于Microsoft.IdentityModel.Web.SessionAuthenticationModule的Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte []标记,SecurityTokenResolver tokenResolver). System.Web.HttpApplication.SyncEventExecutionStep.System.Web上的Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender,EventArgs eventArgs)中的Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken&sessionToken)上的ReadSessionTokenFromCookie(Byte [] sessionCookie) System.Web.HttpApplication.ExecuteStep中的.HttpApplication.IExecutionStep.Execute()(IExecutionStep step,Boolean&completedSynchronously)

•我们已经能够通过使用旧的FedAuth cookie和这个插件来重新生成错误:(注意!我们不确定这是否与PROD上发生的情况相同,但至少它会给出相同的错误我们的记录系统)这很好,但我认为你应该添加一些步骤,了解我们如何能够修改FedAuth cookie的内容,在本地实现这个问题.-你可以使用它:它很简单以前会话中的FedAuth cookie的值(在同一台机器上!不是来自另一台机器,不起作用)并将其粘贴到FedAuth cookie的值中并刷新页面.-

用于修改Cookie的插件,在Chrome中称为"编辑此Cookie": - 如果我们将此Cookie的内容更改为上一个会话的值,并点击刷新(Chrome中的CTRL + R),我们就会得到臭名昭着的TokenSecurityException ID4243和RP呼叫一个联邦FederatedSignout因为我们无法从这种情况中恢复.

退出....

我还应该提一下,我们认真对待IsReferenceMode上的Microsoft MSDN文章标记为"重要",并将其添加到我们的

SessionAuthenticationModule_SessionSecurityTokenCreated事件:

e.SessionToken.IsReferenceMode = true;

取自MSDN:

重要!要在参考模式下运行,Microsoft建议为global.asax.cs文件中的WSFederationAuthenticationModule.SessionSecurityTokenCreated事件提供处理程序,并在SessionSecurityTokenCreatedEventArgs.SessionToken属性中传递的令牌上设置SessionSecurityToken.IsReferenceMode属性.这将确保会话令牌在每个请求的参考模式下运行,并且优于仅在会话认证模块上设置SessionAuthenticationModule.IsReferenceMode属性.

下面是我们的整个SessionAuthenticationModule_SessionSecurityTokenReceived,请检查我在其中添加的评论...它解释了所有内容:

void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
    {
        if (e.SessionToken.ClaimsPrincipal != null)
        {
            DateTime now = DateTime.UtcNow;
            DateTime validTo = e.SessionToken.ValidTo;
            DateTime validFrom = e.SessionToken.ValidFrom;
            TimeSpan lifespan = new TimeSpan(validTo.Ticks - validFrom.Ticks);

            double keyEffectiveLifespan = new TimeSpan(e.SessionToken.KeyExpirationTime.Ticks - e.SessionToken.KeyEffectiveTime.Ticks).TotalMinutes;
            double halfSpan = lifespan.TotalMinutes / 2;

            if (validFrom.AddMinutes(halfSpan) < now && now < validTo)
            {
                SessionAuthenticationModule sam = sender as SessionAuthenticationModule;

                // This will ensure a re-issue of the token, with an extended lifetime, ie "slide". Id deletes the current token from our databasetoken cache (with overriden Remove of the SessionSecurityTokenCache ) and writes a new one into the cache with the overriden AddOrUpdate of the SessionSecurityTokenCache. 
                // it will also write the token back into the cookie ( just the pointer to the cookie, because it's stored in database-cache ) because the IsReferenceMode = True is set
                e.ReissueCookie = true; // Will force the DatabaseSecurityTokenCache'ið to clean up the cache with this, handler.Configuration.Caches.SessionSecurityTokenCache.Remove(key); internally in WIF's SessioAuthenticationModule

                e.SessionToken = sam.CreateSessionSecurityToken(
                    e.SessionToken.ClaimsPrincipal,
                    e.SessionToken.Context,
                    now,
                    now.AddMinutes(lifespan.TotalMinutes),
                    false); // Make persistent, þannig að kakan lifir EKKI af browser-close / tab-lokun:
                {
                    e.SessionToken.IsReferenceMode = true; // Cache on server
                }

                // Not needed, because if ReissueCookie = true;  is set, it WILL to a WriteSessionTokenToCookie internally in WIF
                //FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(e.SessionToken); // <---- er þetta e.t.v. bara það sem við þurfum ? Nei, á ekki að þurfa, er gert þegar tóki er búinn til með CreateSessionSecurityToken
            }
            else if (validTo < now)
            {
                // Fix
                // http://blogs.planbsoftware.co.nz/?p=521                    

                var sessionAuthenticationModule = (SessionAuthenticationModule)sender;
                sessionAuthenticationModule.DeleteSessionTokenCookie(); // <--- is this really needed like the article says ? http://blogs.planbsoftware.co.nz/?p=521
                e.Cancel = true; // This will allow a silent-login if the STS cookie is still valid, e.g. switching between RP's where we're switching from an active RP to a RP which has it's cookie outdated, but the STS's session is still alive. We don't want to prompt the user for a new login, beucase the STS session is still OK!
            }
    }

小智.. 6

这篇文章帮助了我,所以它可以帮助你和其他有这种错误的人.

void Application_OnError()
{
  var ex = Context.Error;
  if (ex is SecurityTokenException){
     Context.ClearError();
     if (FederatedAuthentication.SessionAuthenticationModule != null){
         FederatedAuthentication.SessionAuthenticationModule.SignOut();
     }
   Response.Redirect("~/");
  }
}

从这个链接.

希望它有用!

1 个回答
  • 这篇文章帮助了我,所以它可以帮助你和其他有这种错误的人.

    void Application_OnError()
    {
      var ex = Context.Error;
      if (ex is SecurityTokenException){
         Context.ClearError();
         if (FederatedAuthentication.SessionAuthenticationModule != null){
             FederatedAuthentication.SessionAuthenticationModule.SignOut();
         }
       Response.Redirect("~/");
      }
    }
    

    从这个链接.

    希望它有用!

    2023-02-09 19:06 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有