2010-09-02 13 views
6

Ho bisogno di passare un valore dal client ogni volta che una richiesta viene inviata a WCF e controllare quel valore sul server e decidere di fare o meno la richiesta, qualcuno può scrivere un esempio di questo? Non sono sicuro come sia sta andando essere attuatoWCF e autenticazione

caso: im generare una chiave basata su hardware del cliente e voglio inviare la chiave al server con ogni richiesta per verificare se la chiave è accettata nel db server e poi decidere di elaborare la richiesta o meno.

grazie in anticipo.

+1

Vedi http://stackoverflow.com/questions/964433/how-to-add-a-custom-header-to-every-wcf-calls per passare automaticamente i dati come intestazione. Non so come controllarlo automaticamente sul server, però, ma mi aspetto che ci sia un gancio. – Rup

risposta

1

prima abbiamo bisogno di implementare il comportamento e ispettore nel lato client per inviare chiave per autenticare il client:

class AuthenticationBehaviour : IEndpointBehavior 
{ 
    #region IEndpointBehavior Members 

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
    { 
     AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     clientRuntime.MessageInspectors.Add(inspector); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
    { 
     //AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector); 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
    } 

    class AuthenticationMessageInspector : IClientMessageInspector 
{ 
    private const string HeaderKey = "Authentication"; 

    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 

     if (Session.MachineId == 0) 
     { 
      Session.MachineId = LicenseGenerator.GenerateLicense(); 
     } 


     request.Headers.Add(MessageHeader.CreateHeader(HeaderKey, string.Empty, Session.MachineId)); 
     return null; 
    } 

    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 

    } 
} 

Ora abbiamo bisogno di implementare il comportamento e ispettore nel lato server (servizio WCF) per ispezionare ogni richiesta fatta ed estrarre l'intestazione poi convalidarlo:

public class AuthenticationBehaviour : IEndpointBehavior 
{ 
    #region IEndpointBehavior Members 

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
    { 
     //AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     //clientRuntime.MessageInspectors.Add(inspector); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
    { 
     AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector); 
     //Console.WriteLine("Dispatcher Applied!"); 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
    } 

    #endregion 
} 

    public class AuthenticationMessageInspector : IDispatchMessageInspector 

{ 

    #region Members 
    private string conStr = "", commStr = ""; 
    public IDbConnection Connection { get; set; } 
    public IDbCommand Command { get; set; } 
    public IDataReader Reader { get; set; } 

    #endregion   
    private const string HeaderKey = "Authentication"; 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 
     //Console.WriteLine("recieved Request! "); 
     int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty); 
     if (headerIndex < 0 || string.IsNullOrEmpty(request.Headers.GetHeader<String>(headerIndex))) 
     { 

      throw (new Exception("Access Denied!\n")); 
      return null; 
     } 


     bool valid = Validate(request.Headers.GetHeader<String>(headerIndex)); 
     if (!valid) 
     { 
      Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex) + " and Access Denied!\n"); 
      throw (new Exception("Access Denied!\n" + request.Headers.GetHeader<String>(headerIndex) + " License Number is not athourized! "));   
     } 
     if (headerIndex != -1) 
     { 
      Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex)); 
     } 
     return null; 

    } 

    public void BeforeSendReply(ref Message reply, object correlationState) 
    { 

    } 
} 

ora consente di registrare il comportamento:

  _routingHost.Description.Endpoints[0].Behaviors.Add(new Gateway.Controllers.AuthenticationBehaviour()); 
_routingHost.Open(); 

grazie.

2

Stai cercando un ispettore di messaggi. Controlla questo article.

Edit:

approccio citato è il più semplice nel tuo caso. Creerai l'ispettore dei messaggi del cliente per aggiungere un'intestazione personalizzata e un ispettore dei messaggi per estrarre l'intestazione e convalidare la chiave. Se la chiave non è valida, verrà generata un'eccezione.

La soluzione pulita è quella di creare custom token e cutom credentials ma è davvero complesso quindi, a meno che non si voglia immergersi in profondità nell'implementazione della sicurezza di WCF, utilizzare gli ispettori dei messaggi.

+0

sto generando una chiave basata sull'hardware del client e voglio inviare quella chiave al server con ogni richiesta per verificare se la chiave è accettata nel server db e quindi decidere di elaborare la richiesta o meno – Stacker

+0

Quindi è un autenticazione (basta controllare che il client con la chiave possa accedere al servizio) o autorizzazione (chiavi diverse possono utilizzare diverse serie di operazioni)? –

+0

è sufficiente verificare che il client con chiave possa accedere al servizio – Stacker

1

Ho implementato qualcosa come questo per gestire alcune autenticazioni "personalizzate" in cui i metodi sono consentiti o negati in base allo stato del database. Utilizza l'implementazione PerSession, che consente di evitare di passare quella chiave ogni volta, poiché è possibile mantenere il proxy per la durata dell'esecuzione. Fornisce inoltre alcuni vantaggi in termini di prestazioni eliminando il sovraccarico di istanziare il proxy ripetutamente (potrebbe non essere un problema a seconda del progetto).

  1. implementare il servizio con un InstanceContextMode di "PerSession" [ServiceBehavior (InstanceContextMode = InstanceContextMode.PerSession)]
  2. fornire un metodo di inizializzazione nel servizio che accetta la chiave, e mantiene un riferimento a esso.
  3. Nei metodi del servizio, controllare quella chiave, altre condizioni, ecc. Per determinare cosa è necessario fare.
  4. Ora, quando si crea un'istanza del proxy client, chiamare quel metodo di inizializzazione prima di passare la chiave e da quel punto in avanti è possibile continuare a effettuare chiamate senza di essa.
+0

in realtà l'ho già implementato, grazie mille per aver cercato di aiutare, ho usato un metodo diverso che avrei scritto una risposta a quello presto – Stacker

0

Sono giunto a questo articolo durante il tentativo di implementare un meccanismo di autenticazione su un servizio Rest WCF, stavo cercando di ottenere l'intestazione di autenticazione sul metodo Custom Message Inspector AfterReceiveRequest ma ho riscontrato problemi nel recuperare le intestazioni con System.ServiceModel fornito. Canale.oggetto di messaggio (richiesta var sulla firma del metodo)

public object AfterReceiveRequest(ref Message request, IClientChannel channel, 
    InstanceContext instanceContext) 
    Dim headerIndex = request.Headers.FindHeader(HeaderKey, String.Empty) 

Il headerIndex sarebbe sempre -1, dato questo ho ricercato e trovato che esiste un metodo di estensione alla classe messaggio che consente di convertire il messaggio a un oggetto di tipo System.Net.Http.HttpRequestMessage. Per fare tutto ciò è necessario importare i seguenti assembly: System.ServiceModel.Channel, System.Net.Http.

Dim httpReq As System.Net.Http.HttpRequestMessage = request.ToHttpRequestMessage() 

Dim authValue As String 
If httpReq.Headers.Contains(HeaderKey) Then 
    authValue = httpReq.Headers.GetValues(HeaderKey)(0) 
End If 
Problemi correlati