среда, 14 июля 2010 г.

WCF. Расширение OperationContext.

При создании сервисов порой хочется чтобы из любого места серверного кода можно было получать определенную информацию, например прикладные данные пользователя, какие то данные контекста выполнения. При этом привязать этот контекст хочется к OperationContext.

WCF предоставляет средства расширения, которые позволяют добавлять свои расширения к некоторым инфраструктурным элементам. Подробнее про расширяемость WCF можно почитать  тут. Расскажу о том, как привязать к OperationContext свой собственный контекст выполнения.

Шаг 1. Реализовываем класс-расширение.

Для реализации класса, который будет хранить наш контекст, необходимо реализовать интерфейс IExtension. Данный интерфейс позволяет расширять возможности некоторых инфраструктурных элементов WCF, например, OperationContext. Реализовать необходимо два метода: Attach и Detach.

1: using System.ServiceModel;

2:

3: namespace ContextExtentionSample

4: {

5: public class ContextExtention : IExtension<OperationContext>

6: {

7: // custom data...

8:

9: #region IExtension<OperationContext> Members

10:

11: public void Attach(OperationContext owner)

12: {

13: // attach to OperationCompleted to destroy context

14: owner.OperationCompleted += new EventHandler(delegate (object sender, EventArgs args)

15: {

16: this.Detach((OperationContext)sender);

17: });

18: }

19:

20: public void Detach(OperationContext owner)

21: {

22: // free context data

23: }

24: #endregion

25: }

26: }

Шаг 2. Реализовываем привязку к OperationContext.

При инициализации вашего контекста необходимо означить контекст для OperationContext.

1:ContextExtention extention;

2:extention = new ContextExtention(user.Id, gropIds);

3:OperationContext.Current.Extensions.Add(extention);

Шаг 3. Использвование контекста.

Получить контекст достаточно просто, для этого необходимо просто обратиться к OperationContext следующим образом:

1:OperationContext.Current.Extensions.Find<ContextExtention >()

В итоге, получится контекст, который можно получить в любом месте выполнения операций сервиса начиная от инициализации этого контекста и заканчивая завершением операции (уничтожением OperationContext).

В следующей статье расскажу как расширять InstanceContext.

Posted via email from Комуникликабельность

пятница, 9 июля 2010 г.

WCF. Custom windows autentication

Недавно столкнулся со следующей задачей: сервис должен аутентифицировать Windows пользователя с учетом списка пользователей прикладного приложения, сохраненного в базе. Простого решения не нашел, поскольку точки расшинрения WCF позволяют подвязывать Custom аутентификацию только к аутентификацию по паролю, поэтому появилось такое решение.

Создаем провайдер аутентификации.

public class AutenticationManager : ServiceAuthenticationManager

{

public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<System.IdentityModel.Policy.IAuthorizationPolicy> authPolicy,

Uri listenUri,

ref System.ServiceModel.Channels.Message message)

{

// autenticate base.

ReadOnlyCollection<IAuthorizationPolicy> res = base .Authenticate(authPolicy, listenUri, ref message);

// custom autentication.

User user = DataSession.GetUserByName(ServiceSecurityContext.Current.PrimaryIdentity.Name);

if (user != null )

// return base autentication.

return res;

else

// return none autentication.

return null ;

}

}

 

Затем подвешиваем его при помощи атрибута или конфигурации. С помощью атрибута можно сделать так:

[AttributeUsage(AttributeTargets.Class)]

public class AutenticationBehaviorAttribute : Attribute, IServiceBehavior

{

#region IServiceBehavior Members

public void AddBindingParameters(ServiceDescription serviceDescription,

System.ServiceModel.ServiceHostBase serviceHostBase,

System.Collections.ObjectModel.Collection <ServiceEndpoint> endpoints,

System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { }

 

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)

{

serviceHostBase.Authentication.ServiceAuthenticationManager = new AutenticationManager();

}

 

public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { }

#endregion

}

 

При помощи конфигурации не подвешивал, но думаю это достаточно просто (лень искать), да и нескольк небезопасно на мой взгляд, поскольку это всеже проверка аутентификации и подмена конфигарации ее может отрубить, а вот отменить конфигурирование в коде достаточно проблематично для администратора сервиса.

Далее навешиваем этот аттрибут на реализацию сервиса:

[AutenticationBehavior()]

public class DataService : IDataService

{

}

В итоге, если пользователь не аутентифицирован вашим кодом, то на клиент уходит сообщение с ошибкой «The Caller was not authenticated by the service».

Информации о менеджере аутентификации к сожалению достаточно мало и как с ним работать пока непонятно до конца. Например непонятно какой результат должен быть у метода Autenticate, если аутентификация не прошла. В принципе нормально отрабатываются ситуации с ошибками, однако это не очень хороший вариант. А при передаче на выход пустой коллекции пользователь считается аутентифицированным.

Если у кого то есть соображения какие значения должен возвращать менеджер или ктото знает способ проверки Windows пользователей лучше и/или правильней – вэлкам. 

 

Posted via email from Комуникликабельность