2009-07-05 50 views
10

Antecedentesaplicación web ASP.NET Autenticación con un servicio WCF

Tengo una aplicación web ASP.NET que interactúa con los servicios de WCF. La aplicación web y los servicios de WCF están bajo mi control. La aplicación web ASP.NET utiliza una implementación personalizada del Modelo de Proveedor de Membresía ASP.NET (con contraseñas almacenadas en forma de hash) para autenticar a los usuarios que inician sesión en la aplicación web. Tanto la aplicación web ASP.NET como los servicios WCF tienen acceso a la misma base de datos de miembros.

Dado que los usuarios proporcionarán su contraseña solo una vez, y no quiero tener que almacenar sus contraseñas en ningún lugar ni molestarlas pidiéndoles repetidamente que reabastezcan su contraseña, necesito un mecanismo apropiado para autenticar a los usuarios con el Servicios de WCF.

En base a otras preguntas y respuestas que he visto, estoy considerando un tipo de sesión de inicio de sesión, donde se creará una sesión de inicio de sesión en la base de datos de membresía personalizada cuando el usuario inicie sesión en la aplicación web, con la sesión de inicio de sesión identificada por un GUID, y expiró automáticamente después de un período de inactividad. La aplicación web "recordará" el GUID de la sesión de inicio de sesión para cada usuario conectado (ya sea almacenado en el Ticket de Autenticación de Formularios o en la sesión).

El servicio WCF también proporcionará su propia operación de inicio de sesión aceptando un nombre de usuario y contraseña, y devolviendo un GUID de sesión de inicio de sesión como se describió anteriormente.

El servicio WCF aceptaría entonces el GUID de la sesión de inicio de sesión para todas las demás operaciones y verificará que el GUID representa una sesión de inicio de sesión válida que no ha expirado antes de permitir que la operación continúe.

He leído bastante sobre esto, y hay un montón de material sobre el uso directo del tipo de credencial del nombre de usuario UserName, pero esto requeriría que la aplicación web recuerde la contraseña del usuario, que no lo hace Me parece una gran idea.

Investigué un poco y encontré material en MSDN, pero esto parece un gran esfuerzo para implementar lo que (al menos para mí) parece ser un escenario de uso bastante común.

How to: Create a Custom Token

Pregunta

es el enfoque general de la "sesión de inicio" descrito anteriormente razonable?
Si es así, ¿cuál es la mejor manera de lograrlo?
Si no es así, ¿puede sugerir una alternativa?

+0

Es el servicio WCF accesible desde la red interna solamente? Si ese es el caso, no veo la necesidad de volver a autenticar las solicitudes. –

+0

Disculpe la omisión: el servicio de WCF estará disponible en Internet. –

Respuesta

1

Gracias a todos por su colaboración. Me he decidido por un enfoque (al menos por ahora). Es bastante simple y funciona bien para mis propósitos.

Utilizando el clientCredentialType "nombre de usuario", y un método de inicio de sesión de servicio explícita que devuelve un token de seguridad (detalles generación de tokens omiten por razones de brevedad), el cliente de servicios puede decidir si pasar la contraseña genuina que la propiedad de contraseña en las credenciales del cliente o el token de seguridad en su lugar (obtenido del método de inicio de sesión). Si el cliente es una aplicación web, el token de seguridad se puede almacenar en el ticket de autenticación de formularios, o la sesión, o donde sea.

Utilizando el userNamePasswordValidationMode "Custom" y una implementación personalizada de UserNamePasswordValidator, el validador inspecciona la contraseña para determinar si se trata de un token de seguridad válida o una contraseña - si se trata de una contraseña las credenciales del cliente se autentican con el almacén de usuario (SQL Base de datos del servidor), y si se trata de un token de seguridad, se verifica para asegurarse de que sea válido, no haya caducado y pertenezca al nombre de usuario.

1

Hay dos soluciones posibles que se me ocurren:

En primer lugar, si el servicio WCF es un servicio interno, la aplicación web puede entonces enviar el nombre del usuario que está pidiendo los datos con cada solicitud.

La segunda es que almacena el nombre de usuario y el hash de la contraseña (o la contraseña real) en alguna parte. Ya sea en el estado de la sesión o en la cookie del usuario (una cookie de sesión almacenada en la memoria se transfiere al usuario a través de https). Luego, pase el nombre de usuario y la contraseña al servicio WCF con cada solicitud.

+1

El servicio WCF estará disponible en Internet. Si almaceno un hash de la contraseña, entonces necesito habilitar la autenticación con el servicio WCF usando el hash de la contraseña; por lo que puedo ver, esto efectivamente lo convierte en una contraseña (aunque sea difícil/imposible) adivinar), pero todavía algo que sería "permanentemente" útil si se ve comprometido (al menos hasta que el usuario cambie su contraseña). Usando el enfoque de token de sesión de inicio de sesión que originalmente describí significaría que el token de la sesión de inicio de sesión solo era válido por un período corto y sería mucho menos arriesgado si estuviera en peligro. –

1

Consulte mi respuesta en Storing password in forms authentication cookie - ASP.NET and WCF calls para obtener una solución que no requiera el almacenamiento de contraseñas.

+0

He leído la respuesta a la que hace referencia antes de publicar esta pregunta. Parece un enfoque interesante, pero soy un poco confuso con la mecánica. ¿Podría aclarar o dar un ejemplo? –

+0

@Secret Squirrel, amplié la respuesta en la otra página. –

2

Este es un enfoque muy razonable.

Para hacerlo, configure su punto final de servicio y configúrelo con su proveedor de membresía personalizado (Puede hacer lo mismo con el proveedor de membresía de SQL, no requiere uno personalizado).

En la aplicación web, configura el evento Autenticar del control de inicio de sesión para instanciar un nuevo servidor proxy de servicio y establecer el nombre de usuario/contraseña en las ClientCredentials en el servidor proxy.

Ahora cuando realiza la llamada al Servicio a través del proxy, WCF pasará estas credenciales a través del canal seguro al servicio y las usará para la autenticación.

Ahora solo necesita almacenar el proxy en sesión y usarlo para acceder en el futuro al servicio ya que tiene el estado del canal y una clave privada.

protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e) 
{ 
    bool Authenticated = false; 
    try 
    { 
     MyServiceClient proxy = new MyServiceClient("MyServiceEndpoint"); 
     proxy.ClientCredentials.UserName.UserName = LoginControl.UserName; 
     proxy.ClientCredentials.UserName.Password = LoginControl.Password; 

     //It doesn't really matter what is called or what it does because 
     //Membership Provider for the Service does the authentication. 
     string retval = proxy.login("Logging in"); 

     //Now that channel is established the proxy needs to be kept 
     //since it contains the channel state which includes a private key 
     Session["MyServiceProxy"] = proxy; 
     Authenticated = true; 
    } 
    catch (Exception ex) 
    { 
     //Login Error... 
    } 
    e.Authenticated = Authenticated; 
} 
+0

Creo que su sugerencia es interesante, pero me preocupa lo que sucedería si el canal presentara una falla (error de comunicación, excepción de servicio no administrado, etc.) - la sesión de la aplicación web contendría una referencia a un proxy muerto y no habría manera de crear un nuevo proxy ya que no tendría acceso a la contraseña del usuario. –

+0

Después de haber pensado en su sugerencia un poco más, no creo que este tipo de enfoque sea apropiado. La aplicación web necesita interactuar con múltiples servicios WCF (con las mismas credenciales de usuario) y este enfoque me obligaría a crear un proxy para cada servicio en el momento en que el usuario inicie sesión y guarde en caché todas estas referencias proxy en la sesión. No creo que esto se escale bien y necesito admitir una gran cantidad de usuarios simultáneos en un servidor compartido. –

+0

Cada vez que cree una instancia del proxy, debe pasar por un protocolo de enlace para establecer un canal seguro. Según la configuración, esto puede incluir el intercambio de certificados y la generación y el intercambio de una clave de cifrado efímera. El almacenamiento en caché del proxy elimina este intercambio en todas y cada una de las solicitudes. No estoy seguro de cómo responder la pregunta sobre el canal con errores ya que no he probado este escenario. Si no se restablece automáticamente, entonces probablemente también deba guardar el nombre de usuario/contraseña en alguna parte. No sé si tendrías muchas opciones. – RonnBlack

0

sugeriría a echar un vistazo a Geneva que está dirigido a resolver situaciones como la suya. La idea básica es requerir el mismo token de seguridad, por medio de un HttpModule, tanto para los servicios WCF como para el sitio ASP. El token se lanzará después de autenticarse en su base de datos de miembros y puede contener información útil (reclamos) en el usuario.

Para una introducción, puede leer Bustamante's article.

+0

Había mirado a Ginebra como resultado de leer el artículo de Bustamente hace un par de meses, y parece una posible solución, pero todavía está en versión beta, y desafortunadamente necesito una solución ahora. :-) –

Cuestiones relacionadas