2008-09-24 8 views
7

Aquí está la situación. Tengo un servicio web (C# 2.0), que consiste en (principalmente) una clase que hereda de System.Web.Services.WebService. Contiene algunos métodos, que todos necesitan llamar a un método que verifica si están autorizados o no.Llamar a un determinado método antes de cada llamada al servicio web

Básicamente algo como esto (perdón por la arquitectura, esto es puramente como un ejemplo):

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"; 
    } 
} 

Como se puede ver, el método Validate tiene que ser llamado en cada método. Estoy buscando una manera de poder llamar a ese método, mientras sigo siendo capaz de acceder a los encabezados de jabón de una manera sensata. He visto los eventos en el global.asax, pero no creo que pueda acceder a los encabezados de esa clase ... ¿Puedo?

Respuesta

9

Esto es lo que necesita hacer para que esto funcione correctamente.

Es posible crear su propia SoapHeader personalizado:

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

    public ServiceAuthHeader() {} 
} 

entonces usted necesita un 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; 
     } 
    } 
} 

Y un SoapExtension personalizado:

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); 
     } 
    } 
} 

Luego, en su servicio web agregue el siguiente encabezado a su método:

public ServiceAuthHeader AuthenticationSoapHeader; 

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

Cuando se consumen este servicio, debe crear una instancia de la cabecera personalizada con los valores correctos y adjuntarlo a la solicitud:

private ServiceAuthHeader header; 
private PublicService ps; 

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

string WhatYouWant = ps.GetSomeStuffFromTheCloud(SomeId); 
+0

No es tan sencillo como suponía. Voy a probar esto ahora. –

+0

¡Funciona! Tenga en cuenta que el acceso basado en web de Visual Studio no activa la extensión, ya que no utiliza SOAP para realizar la solicitud. Me hizo rascar mi cabeza por unos minutos. –

1

Puede implementar la llamada extensión SOAP derivando de la clase SoapExtension base. De esta forma, podrá inspeccionar un mensaje SOAP entrante y ejecutar la lógica de validación antes de que se llame a un método web particular.

1

me gustaría echar un vistazo a la adición de un aspecto de la seguridad de los métodos buscas asegurarte Eche un vistazo al PostSharp, y en particular al tipo OnMethodBoundryAspect y al método OnEntry.

Cuestiones relacionadas