У меня возникла сложность при обработке следующего сценария.Как загрузить boottrap для канала WCF, созданного с помощью Unity InjectionFactory
- Я хочу использовать Unity DI Framework для создания нового канала для моего обслуживания, когда это необходимо.
- Служба обеспечена защитой от несанкционированного доступа.
- Услуга не вызывается из службы, размещенной в IIS, но вызывается из самообслуживаемой службы WCF.
Моя текущая проблема возникает в шаге 3 выше - как я могу загружать токен и все же удовлетворять вышеуказанным требованиям? Я опишу решения для каждого шага, хотя, поскольку они нетривиальны и, надеюсь, помогут кому-то еще с этой проблемой.
Решение проблемы 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, но мне нужно будет захватить токен bootstrap, чтобы сделать это. Это довольно хорошо документировано вокруг сети, например. здесь: http://www.cloudidentity.com/blog/2012/11/30/using-the-bootstrapcontext-property-in-net-4-5-2/ Некоторые важные примечания: убедитесь, что у вас есть раздел serviceBehaviors в конфиге, который указывает useIdentityConfiguration = "true", иначе ваш system.identityModel раздел будет проигнорирован, например.
<serviceBehaviors>
<behavior name="">
<serviceCredentials useIdentityConfiguration="true" />
</behavior>
</serviceBehaviors>
А затем ваша система.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);
}));
или на HAPS еще лучше, создать класс, который наследуется от ChannelFactory и добавить метод, который вытягивает, который сочетает в вышеупомянутую логику в единый метод CreateChannelWithIssuedTokenUsingBootstrapContext:
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: Добавляя сложность вышеупомянутых двух проблем, я теперь пытаюсь сделать то же самое за пределами IIS в своей собственной службе WCF с самообслуживанием. Эта же услуга полностью безгражданна, поэтому здесь возникает моя следующая дилемма: Загрузка жеста токена по-прежнему происходит, но это не происходит в правильной теме. Unity, похоже, запускает свой InjectionFactory в отдельном потоке для фактического выполнения служебного вызова.
После выполнения делегата InjectionFactory, CurrentPrincipal является несанкционированным GenericPrincipal. Это отличается от того, что было у нас в вопросе 2 выше - где это утвержденный ClaimsPrincipal - я считаю, что это все настроено на сеанс IIS (пожалуйста, не стесняйтесь исправить, если я ошибаюсь).
достаточно странно, если бы мы тогда заменить выше
container.RegisterType<IMyWcfService>(new PerResolveLifetimeManager(),
new InjectionFactory(
x => new ChannelFactoryWithChannelFactoryOperations<IMyWcfService>("*")
.CreateChannel()));
т.е. теперь просто впрыснуть необеспеченный объект Channel, мы можем заметить, что в нашей самопринятом WCF службе, где мы на самом деле пытаемся взаимодействовать с канал, Thread.CurrentPrincipal - это аутентифицированный ClaimsPrincipal с SecurityToken, правильно загруженный по основному.
Таким образом, проблему можно охарактеризовать следующим образом: , потому что делегат InjectionFactory выполняется в потоке, по которому еще не прошла аутентификация/авторизация, SecurityToken на самом деле не доступен для перехода к созданию канала.
Есть ли у кого-нибудь предложения о том, как я могу решить эту проблему? Разве я уже нарисовал себя в углу с этим конкретным сочетанием самодостаточного WCF и единства?
Спасибо, Clint