WCF Web 服务中的安全上下文令牌无效或过期
Posted
技术标签:
【中文标题】WCF Web 服务中的安全上下文令牌无效或过期【英文标题】:Invalid or expired security context token in WCF web service 【发布时间】:2010-10-29 02:16:06 【问题描述】:全部,
我有一个使用服务帐户(VM,Windows 2003 SP2)在 IIS 下托管的 WCF Web 服务(我们称之为服务“B”)。该服务公开了一个使用默认值的 WSHttpBinding 的端点,除了 maxReceivedMessageSize、maxBufferPoolSize、maxBufferSize 和一些已增加的超时。
Web 服务已使用 Visual Studio 负载测试框架对大约 800 个并发用户进行了负载测试,并且成功通过了所有测试,没有引发异常。单元测试中的代理已从配置中创建。
有一个 sharepoint 应用程序使用 Office Sharepoint Server 搜索服务来调用 Web 服务“A”和“B”。应用程序将从服务“A”获取数据以创建将发送到服务“B”的请求。来自服务“B”的响应被编入索引以供搜索。代理是使用 ChannelFactory 以编程方式创建的。
当服务“A”花费不到 10 分钟时,对服务“B”的调用成功。但是,当服务“A”需要更多时间(约 20 分钟)时,对服务“B”的调用会引发以下异常:
异常消息:从另一方收到不安全或不正确安全的故障。故障代码和细节见内部FaultException 内部异常消息:无法处理该消息。这很可能是因为操作 'namespace/OperationName' 不正确,或者因为消息包含无效或过期的安全上下文令牌,或者因为绑定之间存在不匹配。如果服务由于不活动而中止通道,则安全上下文令牌将无效。为防止服务过早中止空闲会话,请增加服务端点绑定的接收超时。
绑定设置相同,客户端服务器和Web服务服务器的时间与Windows时间服务同步,时区相同。
当我查看托管 Web 服务“B”的服务器时,我可以看到正在记录以下安全错误:
来源:安全
类别:登录/注销
事件 ID:537
用户 NT AUTHORITY\SYSTEM
登录失败:
原因:登录时出错
登录类型:3
登录过程:Kerberos
身份验证包:Kerberos
状态码:0xC000006D
子状态码:0xC0000133
在线阅读一些博客后,状态码表示STATUS_LOGON_FAILURE,子状态码表示STATUS_TIME_DIFFERENCE_AT_DC。但我已经检查了服务器和客户端时钟,并且它们已同步。
我还注意到安全令牌似乎缓存在客户端服务器的某个位置,因为它们有另一个进程使用相同的服务帐户调用 Web 服务“B”并在第一次调用时成功获取数据。然后他们开始更新办公室共享点服务器搜索服务索引的过程,但它失败了。然后,如果他们再次调用第一个进程,它也会失败。
有没有人遇到过此类问题或有什么想法?
问候,
--达米安
【问题讨论】:
【参考方案1】:10 分钟是默认接收超时。如果您的代理闲置超过 10 分钟,则该代理的安全会话将被服务器中止。启用日志记录,您将在服务器的诊断日志中看到这一点。您报告的错误消息适合此行为。 在系统诊断文件中搜索“SessionIdleManager”。如果你找到了,以上就是你的问题了。
试一试,为客户端和服务器设置建立安全上下文="false"。
【讨论】:
【参考方案2】:不要在 using 语句中调用服务操作。而是使用诸如...的模式
client = new ServiceClient("Ws<binding>")
try
client.Operation(x,y);
client.Close();
catch ()
client.Abort();
我不明白为什么会这样,但我猜当代理超出 using 语句的范围时,不会调用 Close。然后服务会等待直到 receiveTimeout(在绑定上)过期,然后中止连接,导致后续调用失败。
【讨论】:
我停止使用使用声明进行服务。如果我需要处理它,请调用显式 ((IDispose)Service).Dispose();终于 using语句的问题是,如果在调用过程中出现异常,using语句会在客户端调用Dispose(),客户端会调用底层通道的Close()。由于连接已经出现故障,这将引发另一个异常,因此第一个异常将永远不会出现。【参考方案3】:我认为这里发生的事情是您的频道正在超时(正如您所怀疑的那样)。
如果我理解正确,超时的不是对服务 A 的调用,而是对服务 B 的调用,在您之前打电话给你。
我猜您是在在调用服务A之前创建频道,而不是及时(即在调用服务之前) B)。您应该在使用它之前创建通道(代理、服务客户端),例如:
AResponse aResp = null;
BResponse bResp = null;
using (ServiceAProxy proxyA = new ServiceAProxy())
aResp = proxyA.DoServiceAWork();
using (ServiceBProxy proxyB = new ServiceBProxy())
bResp = proxyB.DoOtherork(aResp);
return bResp;
不过,我相信,一旦您解决了那个问题(服务 B 超时),您就会意识到 sharepoint 应用的代理(称为服务 A)将超时。 为了解决这个问题,您可能希望将服务模型从请求-响应更改为发布-订阅模型。
对于长期运行的服务,您会希望您的 sharepoint 应用订阅服务 A,并让服务 A 在准备就绪时发布其结果 - 无论需要多长时间。
Juval Lowey 编写的Programming WCF Services (O'Reilly) 有很好的解释,IDesign(Juval 的公司)发布了a great set of coding standards for WCF,以及一个很棒的Publish-Subscribe Framework 的代码。
希望这会有所帮助, 阿萨夫。
【讨论】:
【参考方案4】:我刚才实际上是通过做一些愚蠢的事情触发了这个错误。我有一个修改系统日期的单元测试,以测试一些基于时间的功能。而且我猜我创建上下文和调用我的方法之间的明显时间差(由于系统日期的更改)导致某些内容过期。
【讨论】:
以上是关于WCF Web 服务中的安全上下文令牌无效或过期的主要内容,如果未能解决你的问题,请参考以下文章
加载操作中的 BigQuery 错误:令牌无效 - 令牌无效:无状态令牌已过期
了解 Web 身份验证上下文中的 JSON Web 令牌 (JWT)