visual studio net example create crear application .net wcf web-services
aquí

.net - net - web service c# visual studio 2017



WCF, ASP.NET proveedor de membresía y servicio de autenticación (6)

He escrito una aplicación de Silverlight 2 que se comunica con un servicio de WCF (BasicHttpBinding). El sitio que hospeda el contenido de Silverlight está protegido mediante un proveedor de membresía ASP.NET. Puedo acceder al usuario actual utilizando HttpContext.Current.User.Identity.Name desde mi servicio WCF, y he activado AspNetCompatibilityRequirementsMode.

Ahora quiero escribir una aplicación de Windows usando exactamente el mismo servicio web. Para gestionar la autenticación, he habilitado el servicio de autenticación y puedo llamar al "inicio de sesión" para autenticar a mi usuario ... Okey, todo bien ... Pero ¿cómo diablos puedo obtener esa cookie de autenticación en mi otro cliente de servicio?

Ambos servicios están alojados en el mismo dominio

  • MyDataService.svc <- el que trata con mis datos
  • AuthenticationService.svc <- al que tiene que llamar la aplicación de Windows para autenticarse.

No quiero crear un nuevo servicio para el cliente de Windows, o usar otro enlace ...

Los Servicios de aplicación de cliente son otra alternativa, pero todos los ejemplos están limitados para mostrar cómo obtener el usuario, los roles y su perfil ... Pero una vez que seamos autenticados con los Servicios de aplicación de cliente, debería haber una forma de obtener esa cookie de autenticación. adjunto a mis clientes de servicio cuando vuelvo a llamar al mismo servidor.

Según la opinión de los colegas, la solución es agregar un punto final wsHttpBinding, pero espero poder solucionarlo ...


Los servicios web, como los creados por WCF, a menudo se usan mejor de forma "sin estado", por lo que cada llamada a un servicio web comienza de nuevo. Esto simplifica el código del servidor, ya que no es necesario tener una "sesión" que recuerde el estado del cliente. También simplifica el código del cliente, ya que no es necesario guardar tickets, cookies u otros geegaws que supongan algo sobre el estado del servidor.

Crear dos servicios en la forma que se describe introduce statefulness. El cliente está "autenticado" o "no autenticado", y MyDataService.svc tiene que averiguar cuál.

Da la casualidad, he encontrado que WCF funciona bien cuando el proveedor de membresía se usa para autenticar cada llamada a un servicio. Entonces, en el ejemplo dado, desearía agregar los gubbins de autenticación del proveedor de membresía a la configuración del servicio para MyDataService, y no tener un servicio de autenticación por separado.

Para más detalles, consulte el artículo de MSDN aquí .

[Lo que es muy atractivo para mí, ya que soy flojo, es que esto es completamente declarativo. Simplemente distribuyo las entradas de configuración correctas para mi MembershipProvider en la aplicación.config para la aplicación y! ¡bingo! todas las llamadas a cada contrato en el servicio están autenticadas.]

Es justo señalar que esto no va a ser particularmente rápido. Si está utilizando SQL Server para su base de datos de autenticación, tendrá al menos una, tal vez dos llamadas a procedimientos almacenados por llamada de servicio. En muchos casos (especialmente para enlaces HTTP), la sobrecarga de la llamada de servicio será mayor; si no, considere rodar su propia implementación de un proveedor de membresía que almacena en caché las solicitudes de autenticación.

Una cosa que esto no ofrece es la capacidad de proporcionar una capacidad de "inicio de sesión". Para eso, puede proporcionar un contrato de servicio (¡autenticado!) Que no haga nada (salvo generar un error si falla la autenticación), o puede usar el servicio del proveedor de membresía como se describe en el artículo referenciado original.


Finalmente encontré la manera de hacer que esto funcione. Para la autenticación estoy usando el " Servicio de Autenticación WCF ". Al autenticar el servicio, intentará establecer una cookie de autenticación. Necesito sacar esta cookie de la respuesta y agregarla a cualquier otra solicitud hecha a otros servicios web en la misma máquina. El código para hacer eso se ve así:

var authService = new AuthService.AuthenticationServiceClient(); var diveService = new DiveLogService.DiveLogServiceClient(); string cookieHeader = ""; using (OperationContextScope scope = new OperationContextScope(authService.InnerChannel)) { HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty(); OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty; bool isGood = authService.Login("jonas", "jonas", string.Empty, true); MessageProperties properties = OperationContext.Current.IncomingMessageProperties; HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name]; cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie]; } using (OperationContextScope scope = new OperationContextScope(diveService.InnerChannel)) { HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty(); OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest); httpRequest.Headers.Add(HttpRequestHeader.Cookie, cookieHeader); var res = diveService.GetDives(); }

Como puede ver, tengo dos clientes de servicio, uno para el servicio de autenticación y otro para el servicio que voy a usar. El primer bloque llamará al método de inicio de sesión y tomará la cookie de autenticación de la respuesta. El segundo bloque agregará el encabezado a la solicitud antes de llamar al método de servicio "GetDives".

No estoy contento con este código, y creo que una mejor alternativa podría ser utilizar "Referencia web" en lugar de "Referencia de servicio" y usar la pila .NET 2.0 en su lugar.


Es posible ocultar gran parte del código adicional detrás de un inspector de mensajes personalizado y el comportamiento, por lo que no es necesario que se ocupe de retocar el OperationContextScope usted mismo.

Trataré de burlarme de algo más tarde y enviártelo.

--larsw


Debería echar un vistazo al objeto CookieContainer en System.Net. Este objeto permite que un cliente que no sea navegador se atenga a las cookies. Esto es lo que mi equipo usó la última vez que nos encontramos con ese problema.

Aquí hay un breve artículo sobre cómo usarlo. Puede haber otros mejores, pero esto debería ayudarlo a comenzar.

Fuimos a la ruta sin estado para nuestro conjunto actual de servicios WCF y la aplicación Silverlight 2. Es posible hacer que Silverlight 2 trabaje con servicios enlazados con la seguridad TransportWithMessageCredential, aunque requiere un código de seguridad personalizado del lado de Silverlight. El resultado es que cualquier aplicación puede acceder a los servicios simplemente configurando el nombre de usuario y la contraseña en los encabezados de los mensajes. Esto se puede hacer una vez en una implementación personalizada de IRequestChannel para que los desarrolladores nunca tengan que preocuparse por establecer los valores ellos mismos. Aunque WCF tiene una manera fácil para que los desarrolladores hagan esto, creo que es serviceProxy.Security.Username y serviceProxy.Security.Password o algo igualmente simple.


Escribí esto hace un tiempo cuando usaba Client Application Services para autenticarme contra servicios web. Utiliza un inspector de mensajes para insertar el encabezado de la cookie. Hay un archivo de palabras con documentación y un proyecto de demostración. Aunque no es exactamente lo que estás haciendo, está bastante cerca. Puedes descargarlo desde aquí .


En el cliente, modifique su etiqueta <binding> para el servicio (dentro de <system.serviceModel>) para incluir: allowCookies = "true"

La aplicación debería ahora conservar la cookie y usarla. Notará que IsLoggedIn ahora devuelve verdadero después de iniciar sesión; devuelve falso si no permite las cookies.