Вызовите определенный метод перед каждым вызовом webservice

вот ситуация. У меня есть веб-сервис (C# 2.0), который состоит (в основном) из класса, наследуемого от System.Сеть.Сервисы.Вебсервис. Он содержит несколько методов, которые все должны вызывать метод, который проверяет, авторизованы они или нет.

В основном что-то вроде этого (простите архитектуру, это чисто в качестве примера):

public class ProductService : WebService
{
    public AuthHeader AuthenticationHeader;

    [WebMethod(Description="Returns true")]
    [SoapHeader("AuthenticationHeader")]        
    public bool MethodWhichReturnsTrue()
    {
        if(Validate(AuthenticationHeader))
        {
            throw new SecurityException("Access Denied");
        }
        return true;
    }

    [WebMethod(Description="Returns false")]
    [SoapHeader("AuthenticationHeader")]        
    public bool MethodWhichReturnsFalse()
    {
        if(Validate(AuthenticationHeader))
        {
            throw new SecurityException("Access Denied");
        }
        return false;
    }

    private bool Validate(AuthHeader authHeader)
    {
        return authHeader.Username == "gooduser" && authHeader.Password == "goodpassword";
    }
}

Как видите, метод Validate должен вызываться в каждом методе. Я ищу способ назвать это метод, при этом все еще имея возможность получить доступ к заголовкам soap в здравом уме. Я посмотрел на события в global.asax, но я не думаю, что могу получить доступ к заголовкам в этом классе... Я Могу?

3 ответов


вот что вам нужно сделать, чтобы заставить это работать правильно.

можно создать свой собственный SoapHeader:

public class ServiceAuthHeader : SoapHeader
{
    public string SiteKey;
    public string Password;

    public ServiceAuthHeader() {}
}

тогда вам нужен SoapExtensionAttribute:

public class AuthenticationSoapExtensionAttribute : SoapExtensionAttribute
{
    private int priority;

    public AuthenticationSoapExtensionAttribute()
    {
    }

    public override Type ExtensionType
    {
        get
        {
            return typeof(AuthenticationSoapExtension);
        }
    }

    public override int Priority
    {
        get
        {
            return priority;
        }
        set
        {
            priority = value;
        }
    }
}

и пользовательское SoapExtension:

public class AuthenticationSoapExtension : SoapExtension
{
    private ServiceAuthHeader authHeader;

    public AuthenticationSoapExtension()
    {
    }

    public override object GetInitializer(Type serviceType)
    {
        return null;
    }

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
    {
        return null;
    }

    public override void Initialize(object initializer)
    {        
    }

    public override void ProcessMessage(SoapMessage message)
    {
        if (message.Stage == SoapMessageStage.AfterDeserialize)
        {
            foreach (SoapHeader header in message.Headers)
            {
                if (header is ServiceAuthHeader)
                {
                    authHeader = (ServiceAuthHeader)header;

                    if(authHeader.Password == TheCorrectUserPassword)
                    {
                        return;  //confirmed
                    }
                }
            }

            throw new SoapException("Unauthorized", SoapException.ClientFaultCode);
        }
    }
}

затем в вашем веб-сервисе добавьте следующий заголовок к вашему методу:

public ServiceAuthHeader AuthenticationSoapHeader;

[WebMethod]
[SoapHeader("AuthenticationSoapHeader")]
[AuthenticationSoapExtension]
public string GetSomeStuffFromTheCloud(string IdOfWhatYouWant)
{
  return WhatYouWant;
}

при использовании этой службы необходимо создать экземпляр пользовательского заголовка с правильными значениями и присоединить его к запрос:

private ServiceAuthHeader header;
private PublicService ps;

header = new ServiceAuthHeader();
header.SiteKey = "Thekey";
header.Password = "Thepassword";
ps.ServiceAuthHeaderValue = header;

string WhatYouWant = ps.GetSomeStuffFromTheCloud(SomeId);

вы можете реализовать так называемое расширение SOAP, выведя из SoapExtension base класса. Таким образом, Вы сможете проверить входящее сообщение SOAP и выполнить логику проверки перед вызовом определенного веб-метода.


Я бы взглянул на добавление аспекта безопасности к методам, которые вы хотите защитить. Взгляните на PostSharp, и, в частности, тип OnMethodBoundryAspect и метод OnEntry.