2009-04-27 16 views
8

Estoy tratando de exponer un servicio WCT REST y solo los usuarios con nombre de usuario y contraseña válidos podrán acceder a él. El nombre de usuario y la contraseña se almacenan en una base de datos SQL.¿Cómo transfiere las credenciales de usuario de WebClient a un servicio WCF REST?

Aquí está el contrato de servicios:

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

Aquí es la configuración de 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> 

Yo soy el acceso al servicio a través de la clase WebClient dentro de una aplicación de Silverlight. Sin embargo, no he podido averiguar cómo pasar las credenciales de usuario al servicio. Probé varios valores para client.Credentials pero ninguno de ellos parece activar el código en mi validador personalizado. Recibo el siguiente error: la conexión subyacente se cerró: se produjo un error inesperado en un envío.

Aquí hay un código de ejemplo que he intentado:

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

Si fijo el modo de seguridad en Ninguno, todo funciona. También probé otros valores de clientCredentialType y ninguno funcionó. También auto-alojé el servicio WCF para eliminar los problemas relacionados con IIS que intentan autenticar a un usuario antes de que el servicio tenga una oportunidad.

Cualquier comentario sobre cuáles son los problemas subyacentes sería muy apreciado. Gracias.

Actualización: Gracias a las excelentes sugerencias de Mehmet. Esta es la configuración de rastreo que tenía:

<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> 

Pero yo no vi ningún mensaje que viene de mi cliente de Silverlight. En cuanto a https vs http, https he utilizado de la siguiente manera:

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

Sin embargo, no ha configurado ningún certificado SSL. ¿Este es el problema?

+0

Alex, necesita configurar su servicio para usar el canal de transporte seguro (https). Las vinculaciones en el cliente y el servidor deberían coincidir. Si aloja su servicio en IIS, también deberá configurar SSL para su sitio. Es posible que también necesite aumentar la verbosidad en su rastreo para obtener más detalles. Eche un vistazo a las opciones. Service Configuration Editor facilita la edición de las configuraciones de WCF. –

+0

Mehmet, gracias. "Configuré" mi servicio para usar https dentro del URI de la dirección base. Para la instancia de WebClient, especifiqué la misma dirección con "https" (es decir, https: // localhost: 6600). ¿Son incorrectos? ¿Cómo los configuraría de otra manera? En cuanto al rastreo, lo configuré para Verbose, que se supone que debe registrar todo. Logó más cosas, pero no vi nada procedente del cliente de Silverlight. Gracias. –

+0

¿Cómo se configura WCF en el lado del cliente, especialmente las vinculaciones? ¿Ha configurado IIS y su servicio para SSL? –

Respuesta

0

En primer lugar, es posible que desee agregar el seguimiento WCF a su servicio para obtener más detalles. En segundo lugar, creo que el problema podría ser que está enviando credenciales de usuario en texto claro y WCF no permite la transmisión de credenciales de usuario en texto claro sobre un canal de transporte no seguro. Por lo tanto, intente utilizar https o especifique un algoritmo de cifrado para proteger las credenciales de los usuarios en lugar de http.

1

Dado que está utilizando la autenticación 'Básica', debe enviar el nombre de usuario y la contraseña en el encabezado de la solicitud. Se muestra el ejemplo de cómo agregar manualmente las credenciales a la cabecera a continuación:

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

¿cómo puedo implementar esto con la autenticación 'NTLM'? –

+0

Mira esto: http://allen-conway-dotnet.blogspot.com/2010/01/how-to-create-aspnet-windows.html o este http://msdn.microsoft.com/en-us/ library/ff648505.aspx para ver ejemplos sobre cómo realizar la autenticación de Windows Style con WCF. – atconway

0

Lo atconway sugirió anteriormente parece forma correcta, pero su servicio tiene que leer base de 64 datos de cadena de la cabecera y convertir de nuevo a cadena y luego autenticar . Pero necesita autenticarse en cada llamada.

Un enfoque más es utilizar una clave segura. y el token de

  1. Cada cliente tiene clave segura que envía al primer requerimiento, probablemente en la cabecera.
  2. Puede generar claves como key = MD5Hash (nombre de usuario + contraseña);
  3. En respuesta obtiene token el, el token se envía en cada pedido . Token puede ser Guid. Cada token expiró después de x minutos.
  4. En el lado del servidor puede mantener un diccionario singleton como Dictionay, para verificar la caducidad del token cuando la hora actual> hora de expiración lo elimina del diccionario.
  5. Para renovar sesiones, renueve el método de sesión en su código.

Para mayor seguridad extream

Tener par de claves pública/privada, el cliente va a cifrar los datos de mensaje completo utilizando la clave pública y usted descifrar utilizando la clave privada.

Cuestiones relacionadas