还没有看到很多与日内瓦相关的问题,我也在日内瓦论坛上发布了这个问题......
我正在处理一个场景,我们有一个具有广泛安装基础的 win forms 应用程序,它将在整个操作过程中对我们集中托管的各种服务发出频繁的调用。
这些服务都使用日内瓦框架,所有客户都应该首先调用我们的 STS 以获取令牌以允许访问服务。
开箱即用,使用 ws2007FederationHttpBinding,可以将应用程序配置为在每次服务调用之前从 STS 检索令牌,但显然这不是最有效的方式,因为我们几乎重复了调用服务的工作。
或者,我已经实现了从应用程序“手动”检索令牌所需的代码,然后在对服务调用操作时传递相同的预检索令牌(基于 WSTrustClient 示例和论坛上的帮助);效果很好,所以我们确实有一个解决方案,但我认为它不是很优雅,因为它需要在代码中构建 WCF 通道,远离美妙的 WCF 配置。
我更喜欢 ws2007FederationHttpBinding 方法,在这种方法中,客户端只需像任何其他 WCF 服务一样调用该服务,而无需了解有关日内瓦的任何信息,并且绑定负责令牌交换。
然后有人(乔恩辛普森)给了我 [我认为是] 一个好主意 - 添加一个服务,托管在应用程序本身中以缓存本地检索到的令牌。本地缓存服务将执行与 STS 相同的合约;当接收到请求时,它会检查是否存在缓存令牌,如果存在则返回它,否则它将调用“真实”STS,检索新令牌,缓存并返回它。客户端应用程序仍然可以使用 ws2007FederationHttpBinding,但不是将 STS 作为颁发者,而是使用本地缓存;
通过这种方式,我认为我们可以实现两全其美 - 在没有服务特定的自定义代码的情况下缓存令牌;我们的缓存应该能够处理所有 RP 的令牌。
我创建了一个非常简单的原型来看看它是否有效,并且 - 不幸的是有点不足为奇 - 我有点卡住了 -
我的本地服务(当前是控制台应用程序)获取请求,并且 - 第一次 - 调用 STS 以检索令牌,将其缓存并成功将其返回给客户端,随后客户端使用它来调用 RP。一切正常。
然而,第二次,我的本地 cahce 服务尝试再次使用相同的令牌,但客户端失败并出现 MessageSecurityException -
“安全处理器无法在消息中找到安全标头。这可能是因为消息是不安全的错误,或者是因为通信双方之间存在绑定不匹配。如果为安全配置了服务并且客户端是不使用安全性。”
是否有什么东西阻止了同一个令牌被多次使用?我对此表示怀疑,因为当我按照 WSTrustClient 示例重用令牌时,它运行良好;我错过了什么?我的想法可能吗?一个好?
这是本地缓存的(非常基本的,在这个阶段)主要代码位 -
static LocalTokenCache.STS.Trust13IssueResponse cachedResponse = null;
public LocalTokenCache.STS.Trust13IssueResponse Trust13Issue(LocalTokenCache.STS.Trust13IssueRequest request)
{
if (TokenCache.cachedResponse == null)
{
Console.WriteLine("cached token not found, calling STS");
//create proxy for real STS
STS.WSTrust13SyncClient sts = new LocalTokenCache.STS.WSTrust13SyncClient();
//set credentials for sts
sts.ClientCredentials.UserName.UserName = "Yossi";
sts.ClientCredentials.UserName.Password = "p@ssw0rd";
//call issue on real sts
STS.RequestSecurityTokenResponseCollectionType stsResponse = sts.Trust13Issue(request.RequestSecurityToken);
//create result object - this is a container type for the response returned and is what we need to return;
TokenCache.cachedResponse = new LocalTokenCache.STS.Trust13IssueResponse();
//assign sts response to return value...
TokenCache.cachedResponse.RequestSecurityTokenResponseCollection = stsResponse;
}
else
{
}
//...and reutn
return TokenCache.cachedResponse;