在处理下面的场景时,我遇到了相当大的挑战。
我当前的问题发生在上面的步骤3中--我如何引导令牌,然后满足上述2项要求??不过,我将概述每个步骤的解决方案,因为它们不是微不足道的,希望能在这个问题上帮助其他人。
解决问题1:以下代码片段将在任何需要的时候创建一个新的通道实例。
container.RegisterType<IMyWcfService>(new PerResolveLifetimeManager(),
new InjectionFactory(
x => new ChannelFactoryWithChannelFactoryOperations<IMyWcfService>("*")
.CreateChannel()));下面是一些比我做得更好的人的例子:http://unity.codeplex.com/discussions/211736 https://gist.github.com/tracker1/5675161
您还可以使用替代的终身管理器,例如,TransientLifetimeManager在这里工作得很好。
解决问题2:现在真正的困难开始了--我如何在InjectionFactory中包含一个安全令牌?显然,我想使用CreatChannelWithIssuedToken,但我需要获取引导令牌。这是相当好的文档在网络上,例如:http://www.cloudidentity.com/blog/2012/11/30/using-the-bootstrapcontext-property-in-net-4-5-2/一些重要的事情要注意:确保您在配置中有一个指定useIdentityConfiguration="true“的serviceBehaviors节,否则您的system.identityModel部分将被忽略。
<serviceBehaviors>
<behavior name="">
<serviceCredentials useIdentityConfiguration="true" />
</behavior>
</serviceBehaviors>然后,您的system.identityModel部分还应该提供以下功能:
<system.identityModel>
<identityConfiguration>
<securityTokenHandlers>
<securityTokenHandlerConfiguration saveBootstrapContext="true" />
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>然后,如果您已经请求在会话上正确设置它(请参阅我的另一个问题:AJAX call against REST endpoint secured with Thinktecture's IdentityServer STS ),那么每当您访问引导上下文安全令牌时,它将在会话中可用,如下所示:
var bootstrapContext = ((ClaimsIdentity) Thread.CurrentPrincipal.Identity).BootstrapContext
as BootstrapContext;
SecurityToken securityToken = bootstrapContext.SecurityToken;然后,您可以将InjectionFactory更改为如下所示:
container.RegisterType<IControllerConfigurationService>(new PerResolveLifetimeManager(),
new InjectionFactory(
x =>
{
var bootstrapContext = ((ClaimsIdentity)
Thread.CurrentPrincipal.Identity).BootstrapContext as BootstrapContext;
var securityToken = bootstrapContext.SecurityToken;
return new ChannelFactoryWithChannelFactoryOperations<IMyWcfService>("*")
.CreateChannelWithIssuedToken(securityToken);
}));或者更好的方法是创建一个继承自的类,并添加一个将上述逻辑组合到单个ChannelFactory方法中的方法:
public class ChannelFactoryWithChannelFactoryOperations<T> : ChannelFactory<T>
{
protected ChannelFactoryWithChannelFactoryOperations(Type channelType) : base(channelType)
{
}
public ChannelFactoryWithChannelFactoryOperations()
{
}
public ChannelFactoryWithChannelFactoryOperations(string endpointConfigurationName)
: base(endpointConfigurationName)
{
}
public ChannelFactoryWithChannelFactoryOperations(string endpointConfigurationName,
EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress)
{
}
public ChannelFactoryWithChannelFactoryOperations(Binding binding) : base(binding)
{
}
public ChannelFactoryWithChannelFactoryOperations(Binding binding, string remoteAddress)
: base(binding, remoteAddress)
{
}
public ChannelFactoryWithChannelFactoryOperations(Binding binding, EndpointAddress remoteAddress)
: base(binding, remoteAddress)
{
}
public ChannelFactoryWithChannelFactoryOperations(ServiceEndpoint endpoint) : base(endpoint)
{
}
public T CreateChannelWithIssuedTokenUsingBootstrapContext()
{
var bootstrapContext =
((ClaimsIdentity) Thread.CurrentPrincipal.Identity).BootstrapContext as BootstrapContext;
SecurityToken securityToken = bootstrapContext.SecurityToken;
return CreateChannelWithIssuedToken(securityToken);
}
}这样你就可以把它叫做:
container.RegisterType<IMyWcfService>(new PerResolveLifetimeManager(),
new InjectionFactory(
x => new ChannelFactoryWithChannelFactoryOperations<IMyWcfService>("*")
.CreateChannelWithIssuedTokenUsingBootstrapContext()));解决问题3:增加上述两个问题的复杂性,我现在在我自己托管的WCF服务中尝试IIS之外的相同内容。同样的服务是完全无状态的,所以下面是我的下一个两难处境:安全令牌的引导仍然在发生,但是它没有发生在正确的线程上。统一似乎在一个单独的线程中运行它的InjectionFactory到实际的服务调用执行。
也就是说,当上面的InjectionFactory委托执行时,CurrentPrincipal是一个未经授权的GenericPrincipal。这与我们在上面第2期(它是一个授权的ClaimsPrincipal )中的内容不同,我相信这都是由IIS会话设置的(如果我不正确,请随时更正)。
有趣的是,如果我们用
container.RegisterType<IMyWcfService>(new PerResolveLifetimeManager(),
new InjectionFactory(
x => new ChannelFactoryWithChannelFactoryOperations<IMyWcfService>("*")
.CreateChannel()));也就是说,现在只要注入一个不安全的信道对象,我们就可以观察到,在我们自己托管的WCF服务中,我们实际上尝试与通道交互,Thread.CurrentPrincipal是经过身份验证的ClaimsPrincipal,在主体上正确引导SecurityToken。
因此,这个问题可以总结如下:由于InjectionFactory委托在尚未发生身份验证/授权的线程上执行,因此SecurityToken实际上无法传递到创建通道。
有人对我如何解决这个问题有任何建议吗?我是否已经把自己画到了一个角落,与这种自我托管的WCF和统一的特殊组合?
谢谢,克林特
发布于 2014-02-11 05:00:56
我找到了一个办法来做这件事,虽然我希望有一个更好的建议。SessionSecurityTokenHandler ValidateToken方法总是在与InjectionFactory委托相同的线程上执行,因此我们可以在CustomSessionSecurityTokenHandler的ValidateToken方法中设置线程的CurrentPrincipal,如下所示:
public class CustomSessionSecurityTokenHandler: SessionSecurityTokenHandler
{
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
{
var claimsIdentities = base.ValidateToken(token);
Thread.CurrentPrincipal = new ClaimsPrincipal(claimsIdentities);
return claimsIdentities;
}
}然后,需要修改system.identityModel配置以包括自定义securityTokenHandler:
<securityTokenHandlers>
<remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<add type="MyAssembly.CustomSessionSecurityTokenHandler, MyAssembly" />
</securityTokenHandlers>完成此操作后,尝试从Bootstrap上下文访问安全令牌,然后成功:
container.RegisterType<IControllerConfigurationService>(new PerResolveLifetimeManager(),
new InjectionFactory(
x =>
{
var bootstrapContext = ((ClaimsIdentity)
Thread.CurrentPrincipal.Identity).BootstrapContext as BootstrapContext;
var securityToken = bootstrapContext.SecurityToken;
return new ChannelFactoryWithChannelFactoryOperations<IMyWcfService>("*")
.CreateChannelWithIssuedToken(securityToken);
}));请随时加入其他建议!)
谢谢,克林特
https://stackoverflow.com/questions/21693339
复制相似问题