2009-04-27 13 views
8

Sto tentando di esporre un servizio WCT REST e solo gli utenti con nome utente e password validi potrebbero accedervi. Il nome utente e la password sono memorizzati in un database SQL.Come si passano le credenziali dell'utente da WebClient a un servizio REST WCF?

Ecco il contratto di servizio:

public interface IDataService 
{ 
    [OperationContract] 
    [WebGet(ResponseFormat = WebMessageFormat.Json)] 
    byte[] GetData(double startTime, double endTime); 
} 

Ecco la configurazione WCF:

<bindings> 
    <webHttpBinding> 
    <binding name="SecureBinding"> 
     <security mode="Transport"> 
     <transport clientCredentialType="Basic"/> 
     </security> 
    </binding> 
    </webHttpBinding> 
</bindings> 
<behaviors> 
    <serviceBehaviors> 
    <behavior name="DataServiceBehavior"> 
     <serviceMetadata httpGetEnabled="true"/> 
     <serviceCredentials> 
     <userNameAuthentication 
      userNamePasswordValidationMode="Custom" 
      customUserNamePasswordValidatorType= 
       "CustomValidator, WCFHost" /> 
     </serviceCredentials> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 
<services> 
    <service behaviorConfiguration="DataServiceBehavior" name="DataService"> 
    <endpoint address="" binding="webHttpBinding" 
       bindingConfiguration="SecureBinding" contract="IDataService" /> 
    </service> 
</services> 

sto accedere al servizio tramite la classe WebClient all'interno di un'applicazione Silverlight. Tuttavia, non sono stato in grado di capire come passare le credenziali dell'utente al servizio. Ho provato vari valori per client.Credentials ma nessuno di loro sembra attivare il codice nel mio validatore personalizzato. Viene visualizzato il seguente errore: La connessione sottostante è stata chiusa: si è verificato un errore imprevisto in una trasmissione.

Ecco alcuni esempi di codice che ho provato:

WebClient client = new WebClient(); 
    client.Credentials = new NetworkCredential("name", "password", "domain"); 
    client.OpenReadCompleted += new OpenReadCompletedEventHandler(GetData); 
    client.OpenReadAsync(new Uri(uriString)); 

Se ho impostato la modalità di sicurezza su Nessuno, il tutto funziona. Ho anche provato altri valori di clientCredentialType e nessuno di loro ha funzionato. Ho anche auto-ospitato il servizio WCF per eliminare i problemi relativi a IIS cercando di autenticare un utente prima che il servizio abbia una possibilità.

Qualsiasi commento su quali potrebbero essere le questioni di fondo sarebbe molto apprezzato. Grazie.

Aggiornamento: Grazie agli eccellenti suggerimenti di Mehmet. Qui è la configurazione tracciato ho avuto:

<system.diagnostics> 
    <sources> 
     <source name="System.ServiceModel" 
       switchValue="Information, ActivityTracing" 
       propagateActivity="true"> 
     <listeners> 
      <add name="xml" /> 
     </listeners> 
     </source> 
     <source name="System.IdentityModel" switchValue="Information, 
       ActivityTracing" propagateActivity="true"> 
     <listeners> 
      <add name="xml" /> 
     </listeners> 
     </source> 
    </sources> 
    <sharedListeners> 
     <add name="xml" 
      type="System.Diagnostics.XmlWriterTraceListener" 
      initializeData="c:\Traces.svclog" /> 
    </sharedListeners> 
    </system.diagnostics> 

Ma non ho visto alcun messaggio proveniente dal mio client di Silverlight. Per quanto riguarda https vs http, https ho usato come segue:

string baseAddress = "https://localhost:6600/"; 
_webServiceHost = new WebServiceHost(typeof(DataServices), 
       new Uri(baseAddress)); 
_webServiceHost.Open(); 

Tuttavia, non ho configurare alcun certificato SSL. È questo il problema?

+0

Alex, è necessario configurare il servizio per utilizzare il canale di trasporto sicuro (https). I collegamenti su client e server devono corrispondere. Se stai ospitando il tuo servizio su IIS, dovrai anche configurare SSL per il tuo sito. Potrebbe anche essere necessario aumentare la verbosità nella traccia per ottenere maggiori dettagli. Dai un'occhiata alle opzioni. L'editor di configurazione del servizio semplifica la modifica delle impostazioni WCF. –

+0

Mehmet, grazie. Ho "configurato" il mio servizio per utilizzare https nell'URI dell'indirizzo di base. Per l'istanza WebClient, ho specificato lo stesso indirizzo con "https" (ad es. Https: // localhost: 6600). Sono errati? Come li configurereste diversamente? Per quanto riguarda la traccia, l'ho impostato su Verbose che dovrebbe registrare tutto. Ha fatto registrare più cose ma non ho visto nulla proveniente dal client Silverlight. Grazie. –

+0

In che modo WCF è configurato sul lato client, in particolare i binding? Hai configurato IIS e il tuo servizio per SSL? –

risposta

0

Per prima cosa è possibile aggiungere traccia WCF al proprio servizio per ottenere maggiori dettagli. In secondo luogo, credo che il problema potrebbe essere che si inviano credenziali utente in testo non crittografato e WCF non consente la trasmissione di credenziali utente in testo chiaro su un canale di trasporto non protetto. Quindi, prova a utilizzare https o specifica un algoritmo di crittografia per proteggere le credenziali dell'utente su http.

1

Poiché si utilizza l'autenticazione di base, è necessario inviare il nome utente e la password nell'intestazione della richiesta. L'esempio di aggiungere manualmente le credenziali al colpo di testa viene visualizzato sotto:

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"https://localhost:6600/MyWCFService/GetData"); 
//Add a header to the request that contains the credentials 
//DO NOT HARDCODE IN PRODUCTION!! Pull credentials real-time from database or other store. 
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("userName" + ":" + "password")); 
req.Headers.Add("Authorization", "Basic " + svcCredentials); 
//Parse the response and do something with it... 
using (WebResponse svcResponse = (HttpWebResponse)req.GetResponse()) 
{ 
    using (StreamReader sr = new StreamReader(svcResponse.GetResponseStream())) 
    { 
    //Sample parses json response; your code here may be different 
    JavaScriptSerializer js = new JavaScriptSerializer(); 
    string jsonTxt = sr.ReadToEnd(); 
    } 
} 
+0

come posso implementarlo con l'autenticazione 'NTLM'? –

+0

Guarda questo: http://allen-conway-dotnet.blogspot.com/2010/01/how-to-create-aspnet-windows.html o questo http://msdn.microsoft.com/en-us/ library/ff648505.aspx per esempi su come eseguire l'autenticazione in stile Windows con WCF. – atconway

0

Cosa atconway suggerito sopra sembra modo corretto, ma il servizio deve leggere base di 64 dati di stringa da intestazione e riconvertire a stringa e quindi autenticarsi . Ma ha bisogno di autenticarsi su ogni chiamata.

Un altro approccio consiste nell'utilizzare la chiave di sicurezza. e Token

  1. Ogni cliente ha sicuro chiave che manda a prima richiesta, probabilmente nell'intestazione.
  2. È possibile generare chiavi come key = MD5Hash (nome utente + password);
  3. In risposta riceve il token token, il token viene quindi inviato in ogni richiesta . Il token può essere Guid. Ogni token è scaduto dopo x min.
  4. Sul lato server è possibile mantenere un dizionario singleton come Dictionay, per controllare la scadenza del token quando l'ora corrente> ora di scadenza lo rimuove dal dizionario.
  5. Per rinnovare le sessioni, inserire il metodo di rinnovo nel codice.

Per una maggiore sicurezza extream

Avere coppia di chiavi pubblica/privata, client crittografare tutti i dati pubblicare utilizzando la chiave pubblica e voi decifrare usando la chiave privata.

Problemi correlati