¿Cómo implemento el inicio de sesión en un servicio web RESTful?

78

Estoy construyendo una aplicación web con una capa de servicios. La capa de servicios se construirá con un diseño RESTful. La idea es que en algún momento en el futuro podremos crear otras aplicaciones (iPhone, Android, etc.) que utilicen la misma capa de servicios que la aplicación web. Mi pregunta es esta: ¿cómo implemento el inicio de sesión? Creo que tengo problemas para pasar de un diseño basado en verbos más tradicional a un diseño basado en recursos. Si estuviera construyendo esto con SOAP, probablemente tendría un método llamado Iniciar sesión. En REST debería tener un recurso. Tengo dificultades para entender cómo debo construir mi URI para iniciar sesión. Debería ser algo como esto:

http: // miservicio / {nombre de usuario}? p = {contraseña}

EDITAR: La aplicación web front-end utiliza el marco ASP.NET tradicional para la autenticación. Sin embargo, en algún momento del proceso de autenticación, necesito validar las credenciales proporcionadas. En una aplicación web tradicional, haría una búsqueda en la base de datos. Pero en este escenario, estoy llamando a un servicio en lugar de realizar una búsqueda en la base de datos. Entonces necesito algo en el servicio que valide las credenciales proporcionadas. Y además de validar las credenciales proporcionadas, probablemente también necesite algún tipo de información sobre el usuario después de que se haya autenticado correctamente, como su nombre completo, su identificación, etc. Espero que esto aclare la pregunta.

¿O no estoy pensando en esto de la manera correcta? Siento que tengo dificultades para describir mi pregunta correctamente.

Corey

Corey Burnett
fuente

Respuestas:

62

Como ya señaló S.Lott, aquí tenemos dos cosas: inicio de sesión y autenticación

La autenticación está fuera del alcance aquí, ya que esto se discute ampliamente y existe un acuerdo común. Sin embargo, ¿qué necesitamos realmente para que un cliente se autentique con éxito frente a un servicio web RESTful? Bien, una especie de token, llamémoslo token de acceso.

Cliente) Entonces, todo lo que necesito es un token de acceso, pero ¿cómo obtenerlo de manera RESTANTE?
Servidor) ¿Por qué no simplemente crearlo?
Cliente) ¿Cómo viene?
Servidor) Para mí, un token de acceso no es más que un recurso. Por lo tanto, crearé uno para usted a cambio de su nombre de usuario y contraseña.

Por lo tanto, el servidor podría ofrecer la URL del recurso "/ accesstokens", para POSTAR el nombre de usuario y la contraseña, devolviendo el enlace al recurso recién creado "/ accesstokens / {accesstoken}". Alternativamente, devuelve un documento que contiene el token de acceso y un href con el enlace del recurso:

<token de acceso
  id = "{la identificación del token de acceso va aquí; por ejemplo, GUID}"
  href = "/ accesstokens / {id}"
/>

Lo más probable es que, en realidad, no cree el token de acceso como un recurso secundario y, por lo tanto, no incluirá su href en la respuesta.
Sin embargo, si lo hace, ¿el cliente podría generar el enlace en su nombre o no? ¡No!
Recuerde, los servicios web verdaderamente RESTful vinculan los recursos de una manera que el cliente puede navegar por sí mismo sin la necesidad de generar enlaces de recursos.

La pregunta final que probablemente tenga es si debe PUBLICAR el nombre de usuario y la contraseña como un formulario HTML o como un documento, por ejemplo, XML o JSON; depende ... :-)

Patricio
fuente
4
No siguiendo perfectamente a REST, pero sí de una manera simple y medible mejor que otros. Además compartido con buen humor.
Ted Johnson
2
Patrick, ¿estás proponiendo lo mismo que esta respuesta? stackoverflow.com/a/1135995/14731
Gili
¿El código de estado 403 es correcto cuando el nombre de usuario y / o la contraseña no coinciden?
tsobe
Qué idea. Creando recurso 'accesstoken'.
Clasificador
25

No "inicias sesión". Te "autenticas". Mundo de diferencia.

Tiene muchas alternativas de autenticación.

Autenticación HTTP Basic, Digest, NTLM y AWS S3

  • Autenticación HTTP básica y Digest. Esto usa el HTTP_AUTHORIZATIONencabezado. Esto es muy bonito, muy sencillo. Pero puede generar mucho tráfico.

  • Autenticación de nombre de usuario / firma. A veces se llama autenticación "ID y CLAVE". Esto puede usar una cadena de consulta.

    ?username=this&signature=some-big-hex-digest

    Esto es lo que usan lugares como Amazon. El nombre de usuario es el "id". La "clave" es un resumen, similar al que se usa para la autenticación HTTP Digest. Ambas partes deben acordar el resumen para continuar.

  • Algún tipo de autenticación basada en cookies. OpenAM , por ejemplo, se puede configurar como un agente para autenticarse y proporcionar una cookie que su servidor web RESTful luego puede usar. El cliente se autenticaría primero y luego proporcionaría la cookie con cada solicitud RESTful.

S. Lot
fuente
2
@ S.Lott @Corey Los usuarios pueden interactuar absolutamente con los sistemas RESTful. La mayoría de los sitios web HTML estáticos son "servicios" RESTful.
Darrel Miller
7
@Darrel Miller: "Tu idea ... es defectuosa" no proporciona un contexto adecuado ni nada útil. Es algo negativo y no es muy útil.
S.Lott
5
@Darrel Miller: "afirmar que REST se limita a ... es simplemente ridículo". Lo que sea. En lugar de repetir lo que está mal, ¿podría quizás explicar qué está bien? ¿Podría proporcionar una declaración positiva simple en lugar de declaraciones negativas? ¿Podrías explicar qué es REST en lugar de qué no es? Hay un número infinito de cosas que no lo es.
S.Lott
4
@Darrel Miller: 5.2.1.2 Las representaciones parecen bastante claras. Tus comentarios son muy negativos. ¿Podría proporcionar correcciones positivas o actualizaciones en lugar de negatividad? No sé cómo corregir o modificar mi respuesta para satisfacerte, ya que todo lo que estás haciendo es decir que de alguna manera soy "defectuoso" o "estoy difundiendo información incorrecta" o "ridículo". ¿Qué es menos defectuoso, menos incorrecto o menos ridículo?
S.Lott
5
@ S.Lott 1) ​​Los usuarios interactúan con los sistemas RESTful todo el tiempo. 2) HTML es un tipo de medio perfectamente válido para que lo devuelva un sistema RESTful. 3) REST no es un subconjunto de HTTP. REST es un estilo arquitectónico, HTTP es un protocolo. 4) Los sistemas RESTful no se limitan a "servicios web" 5) Los sistemas RESTful pueden simular un inicio de sesión utilizando algún tipo de token de autorización, sin sufrir los problemas relacionados con las sesiones.
Darrel Miller
1

Gran pregunta, bien planteada. Realmente me gusta la respuesta de Patrick. Yo uso algo como

- / users / {username} / loginsession

Con POST y GET gestionados. Entonces publico una nueva sesión de inicio de sesión con credenciales y luego puedo ver la sesión actual como un recurso a través de GET.

El recurso es una sesión de inicio de sesión y puede tener un token de acceso o un código de autenticación, vencimiento, etc.

Curiosamente, mi interlocutor MVC debe presentar un token de clave / portador a través de un encabezado para demostrar que tiene derecho a intentar crear nuevas sesiones de inicio de sesión ya que el sitio MVC es un cliente de la API.

Editar

Creo que algunas otras respuestas y comentarios aquí están resolviendo el problema con un secreto compartido fuera de banda y solo autenticando con un encabezado. Eso está bien en muchas situaciones o para llamadas de servicio a servicio.

La otra solución es hacer fluir un token, OAuth o JWT o de otro modo, lo que significa que el "inicio de sesión" ya ha tenido lugar mediante otro proceso, probablemente una interfaz de usuario de inicio de sesión normal en un navegador que se basa en un formulario POST.

Mi respuesta es para el servicio que se encuentra detrás de esa interfaz de usuario, asumiendo que desea que el inicio de sesión, la autenticación y la administración de usuarios se coloquen en un servicio REST y no en el código MVC del sitio. ES el servicio de inicio de sesión del usuario.

También permite que otros servicios "inicien sesión" y obtengan un token que caduque, en lugar de usar una clave previamente compartida, así como scripts de prueba en una CLI o Postman.

Luke Puplett
fuente
2
Pasa el token en un encabezado, sí. Páselo como parte de la URL, no. La URL se cifra en tránsito cuando usa HTTPS. Sin embargo; la URL también se almacena en el historial del navegador y en los registros del servidor. Existen muchas buenas razones para evitar pasar datos sensibles a la seguridad en los parámetros de consulta de URL.
Craig
0

Dado que ha cambiado bastante desde 2011 ...

Si está dispuesto a usar una herramienta de terceros y se desvía ligeramente de REST para la interfaz de usuario web, considere http://shiro.apache.org .

Shiro básicamente le brinda un filtro de servlet con el propósito de autenticación y autorización. Puede utilizar todos los métodos de inicio de sesión enumerados por @ S.Lott, incluida una autenticación basada en formularios simples.

Filtre las demás URL que requieren autenticación y Shiro hará el resto.

Actualmente estoy usando esto en mi propio proyecto y hasta ahora me ha funcionado bastante bien.

Aquí hay algo más en lo que la gente puede estar interesada. Https://github.com/PE-INTERNATIONAL/shiro-jersey#readme

Medio duplex
fuente
0

Lo primero que hay que entender sobre REST es que es un acceso a recursos basado en tokens. A diferencia de las formas tradicionales, el acceso se otorga en función de la validación de tokens. En palabras simples, si tiene el token correcto, puede acceder a los recursos. Ahora hay muchas otras cosas para la creación y manipulación de tokens.

Para su primera pregunta, puede diseñar una API Restfull. Las credenciales (nombre de usuario y contraseña) se pasarán a su capa de servicio. La capa de servicio luego valida estas credenciales y otorga un token. Las credenciales pueden ser simples nombre de usuario / contraseña o pueden ser certificados SSL. Los certificados SSL utilizan el protocolo OAUTH y son más seguros.

Puede diseñar su URI así: URI para la solicitud de token- > http: // myservice / some-directory / token ? (Puede pasar credenciales en este URI para Token)

Para utilizar este token para acceder a los recursos, puede agregar este [Autorización: Portador (token)] a su encabezado http.

El cliente puede utilizar este token para acceder a diferentes componentes de su capa de servicio. También puede cambiar el período de vencimiento de este token para evitar un uso indebido.

Para su segunda pregunta, una cosa que puede hacer es otorgar un token diferente para acceder a diferentes componentes de recursos de su capa de servicio. Para esto, puede especificar el parámetro de recurso en su token y un gran permiso basado en este campo.

También puede seguir estos enlaces para obtener más información: http://www.codeproject.com/Articles/687647/Detailed-Tutorial-for-Building-ASP-NET-WebAPI-REST

http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

Rishabh Soni
fuente
-4

Me he enfrentado al mismo problema antes. El inicio de sesión no se traduce bien en un diseño basado en recursos.

La forma en que normalmente lo manejo es teniendo un recurso de inicio de sesión y pasando el nombre de usuario y la contraseña en la cadena de parámetros, básicamente haciendo

OBTENER en http: // myservice / login? U = {nombre de usuario} & p = {contraseña}

La respuesta es algún tipo de sesión o cadena de autenticación que luego se puede pasar a otras API para su validación.

Una alternativa a hacer GET en el recurso de inicio de sesión es hacer un POST, a los puristas de REST probablemente no les agradaré ahora :), y pasar las credenciales en el cuerpo. La respuesta sería la misma.

Alex
fuente
11
¿Contraseña? ¿Contraseña de texto sin formato? ¿Como una cadena de consulta? ¿Realmente quiso decir eso, o quiere decir un resumen de la contraseña?
S.Lott
Gracias. Eso tiene sentido. Aquí hay una pregunta de seguimiento: para una aplicación grande, ¿crearía un gran servicio RESTful para todo o dividiría las cosas en diferentes servicios? Estaba pensando en tener un servicio solo para autenticación y luego diferentes servicios para los diferentes módulos de mi aplicación. ¿Hay alguna razón por la que lo haría o no de una forma u otra?
Corey Burnett
3
S. Lott: Depende de lo que intente hacer. Por supuesto, si puedes hacer un resumen, entonces por supuesto. A veces no es posible un resumen. Si la única opción abierta para usted es enviar una contraseña de texto sin formato, hágalo a través de SSL, en este caso también es mejor usar una POST en lugar de GET para evitar que el navegador recuerde lo que envió.
Alex
Corey: No estoy seguro de entender la distinción entre un gran servicio web y muchos diferentes. Por lo general, define su servicio en términos de recursos, agregando solo los pocos que tenga sentido. Sin embargo, creo que me estoy equivocando.
Alex
Alex: digamos que tenía 4 secciones principales diferentes de mi aplicación web: informes, pedidos, descargas y facturas. ¿Tendría sentido tener 4 definiciones de servicio diferentes o solo una definición de servicio? ¿Existen razones específicas por las que no le gustaría dividir las cosas en muchos servicios diferentes?
Corey Burnett