Comprensión profunda de Spring Cloud Security OAuth2 y JWT
OAuth2 es un estándar abierto para la autorización. La idea central es autenticar las identidades de los usuarios a través de varios métodos de autenticación (OAuth2 no se preocupa por los métodos específicos) y emitir tokens (tokens) para que las aplicaciones de terceros puedan hacerlo. Úselos. Este token permite el acceso a recursos específicos dentro de un tiempo limitado y dentro de un alcance limitado. Las principales especificaciones RFC involucradas son RFC6749 (marco de autorización general), RFC6750 (uso de tokens) y RFC6819 (modelo de amenazas). Generalmente, lo que debemos entender es RFC6749. Hay cuatro formas principales de obtener el token, a saber, el modo de código de autorización, el modo simple, el modo de contraseña y el modo de cliente. La forma de obtener el token está fuera del alcance de este artículo. Aquí asumimos que el cliente ha obtenido el token de acceso de alguna manera. Si desea conocer los pasos de autorización específicos de oauth2, puede ir a Understanding OAuth 2.0 del profesor Ruan Yifeng, que tiene instrucciones muy detalladas.
Aquí primero debemos aclarar algunos conceptos importantes en OAuth2:
Después de aclarar los conceptos, puede consultar el proceso de protocolo de enlace del protocolo OAuth2, extraído de RFC6749
Spring Security es un conjunto de marcos de seguridad que pueden controlar los derechos de acceso de los usuarios basándose en RBAC (control de acceso basado en roles). La idea principal es interceptar y filtrar a través de una serie de cadenas de filtros. lista de filtros en ss Por supuesto, también puede personalizar la lista de cadena de filtros extendida a través de un filtro personalizado
El núcleo de esto es FILTER_SECURITY_INTERCEPTOR, que utiliza FilterInvocationSecurityMetadataSource para hacer coincidir los permisos de recursos y AccessDecisionManager para ejecutar políticas de acceso.
En general, la seguridad del acceso a las aplicaciones gira en torno a los dos conceptos centrales de autenticación (Autenticación) y autorización (Autorización). Es decir, primero debe determinar la identidad del usuario y luego determinar si el usuario tiene permiso para acceder al recurso especificado. Hay muchas soluciones para la autenticación. Las principales incluyen CAS, SAML2, OAUTH2, etc. (Desafortunadamente, todas se han utilizado -_- La solución de inicio de sesión único (SSO) de la que hablamos a menudo es esta para la autorización. Los principales son Spring Security y Shiro. Nunca he usado shiro. Se dice que es relativamente liviano. En comparación, Spring Security tiene una arquitectura más compleja.
Al integrar OAuth2 y Spring Security, puede obtener una solución de seguridad completa.
Para facilitar la comprensión, supongamos que hay un sitio de redes sociales llamado "Waishen.com". Cuando el usuario inicia sesión por primera vez, se le pedirá que importe su lista de amigos en Facebook. para poder establecer rápidamente relaciones sociales. El proceso de autorización específico es el siguiente:
No es difícil ver que en este escenario hipotético, washbasin.com es la aplicación de terceros (cliente) y facebook actúa como servidor de autenticación y como servidor. servidor de recursos. Hay varios puntos clave importantes en este proceso en los que debo centrarme, y rara vez se mencionan en otros artículos relacionados con la integración de Spring Security y OAuth2, por lo que es fácil confundirse.
Los estudiantes cuidadosos deberían haber descubierto que en el proceso de autorización estándar de OAuth2, los pasos 5, 6 y 8 no son necesarios a juzgar por la especificación RFC6749 publicada anteriormente, siempre que haya 1 y 2, 3,. Los pasos 4 y 7 completan todo el proceso de acceso a recursos protegidos. De hecho, la especificación del protocolo RFC6749 en sí no se preocupa por la identidad del usuario, solo se preocupa por cómo se emiten los tokens, cómo renovarlos y cómo usarlos para acceder a los recursos protegidos (Facebook solo necesita asegurarse de que los devueltos a Washbasin lo sean). los amigos del usuario actual. En cuanto a Washbasin.com, no es necesario que le importe quién es el usuario actual). Entonces, ¿por qué Spring Security todavía tiene que realizar los pasos 5 y 6? ¡Esto se debe a que Spring Security es un marco de seguridad completo y debe preocuparse por la identidad del usuario! En escenarios de uso reales, OAuth2 generalmente se usa no solo para acceder a recursos protegidos, sino también para el inicio de sesión único (SSO). En el escenario SSO, la identidad del usuario es sin duda el núcleo y el token en sí no contiene información del usuario, por lo que el cliente no puede saber a qué usuario corresponde el token enviado por el servidor de autenticación. Imagine este escenario. Washbasin.com ya no quiere construir su propio sistema de usuario. Quiere utilizar directamente el sistema de usuario de Facebook. Los usuarios de Facebook corresponden uno a uno a los usuarios de washbasin.com (de hecho, muchos sitios web pequeños y medianos). ahora use este modelo. Los usuarios que usan WeChat, QQ, Weibo y otros sitios web inician sesión directamente). En este caso, Washbasin espera obtener la información del usuario después de pasar la autenticación OAuth2. Por lo tanto, la implementación de autenticación OAuth2 convencional actual reservará una interfaz de adquisición de información del usuario, que es el /usuario mencionado anteriormente (aunque esto no es necesario en el proceso de autorización de OAuth2), de modo que después de que el cliente obtenga el token, pueda transportarlo. a través de esta interfaz obtiene información del usuario y completa todo el proceso de SSO. Además, desde la perspectiva de la experiencia del usuario, si no se puede obtener la información del usuario, significa que cada vez que desee acceder a los recursos de Facebook desde Washbasin, deberá ser redirigido para la autenticación y la experiencia del usuario no es buena.
En primer lugar, debe quedar claro que OAuth2 no es un marco de SSO, pero puede implementar funciones de SSO. El siguiente es un archivo de configuración que utiliza github como servidor de autenticación OAuth2
Puede ver que accessTokenUri y userAuthorizationUri son configuraciones necesarias para completar el proceso de autorización OAuth2, y userInfoUri es necesario para que el marco de seguridad Spring complete el SSO. . Buscado. Para resumir: al configurar el recurso de información del usuario como un recurso protegido, puede usar la tecnología OAuth2 para implementar el inicio de sesión único (SSO), y Spring Security OAuth2 es una implementación de esta solución SSO de OAuth2.
Después de que Spring Security llame con éxito a la interfaz de usuario, construirá un objeto OAuth2Authentication. Este objeto es un superconjunto del objeto UsernamePasswordAuthenticationToken que usamos habitualmente. Encapsula un UsernamePasswordAuthenticationToken estándar y también lo incluye en detalle. Al obtener cierta información clave necesaria en la autenticación OAuth2 (como tokenValue, tokenType, etc.), se completa el proceso de autenticación de inicio de sesión SSO. Si un usuario posterior desea acceder a los recursos protegidos nuevamente, Spring Security solo necesita extraer el token del usuario del principal y luego acceder al servidor de recursos, sin necesidad de autorización del usuario cada vez.
Una cosa a tener en cuenta aquí es que en este momento, la sesión entre el navegador y el cliente aún se mantiene a través del mecanismo tradicional de sesión de cookies, no a través de tokens. De hecho, durante el proceso SSO, el acceso al token solo se utiliza cuando la información del usuario se obtiene entre el cliente y el servidor de recursos. La información del token se almacena en la sesión del cliente, no localmente en el usuario. Esto es algo que no entendía antes. Pensé que los tokens también se usaban entre navegadores y clientes, lo que tomó muchos desvíos. Para Spring Security, ya sea que use cas, saml2 u Oauth2 para implementar SSO, finalmente establece una sesión. con el usuario. La forma de conservarlo es la misma.
Según lo dicho antes, no es difícil ver que existe una diferencia esencial entre la solución SSO OAuth2 y los marcos SSO puros como CAS y SAML2. En CAS y SAML2, no existe el concepto de servidor de recursos, solo los conceptos de cliente de autenticación (aplicación que necesita verificar la información del cliente) y servidor de autenticación (aplicación que proporciona servicios de autenticación). En CAS, estos se denominan cas-client y cas-server. En SAML2, se denominan proveedores de servicios y proveedores de identidad. Se puede ver que las especificaciones de CAS y SAML2 están diseñadas inherentemente para SSO y se tiene en cuenta la información del usuario. en la estructura del mensaje (la especificación SAML2 incluso incluye información de permisos), y OAuth2 en sí no está diseñado específicamente para SSO. Es principalmente para resolver el problema del acceso autorizado de terceros a los recursos, por lo que en términos de información del usuario, se requiere una interfaz adicional. es necesario proporcionar.
En este ejemplo de Washbasin.com, vemos que el servidor de recursos y el servidor de autenticación están juntos (ambos Facebook). En el escenario de Internet, generalmente es difícil encontrar un tercero independiente y autorizado. Centro de certificación de tres partes (es difícil imaginar que el espacio QQ de Tencent esté autorizado a través del centro de certificación de Alipay, y también es difícil imaginar que el uso de los servicios de Google requiera autorización a través de Amazon). Pero si es dentro de la empresa, en realidad existen muchos escenarios de este tipo, especialmente bajo la arquitectura de microservicios. Hay una gran cantidad de servicios que brindan acceso a recursos externos y todos necesitan control de permisos. Entonces, lo más razonable es, por supuesto, establecer un centro de autenticación unificado en lugar de tener un centro de autenticación para cada servicio. Como también hemos introducido antes, el token en sí no contiene información del usuario. Después de la separación, ¿cómo verifica el servidor de recursos la autenticidad del token después de recibir la solicitud? ¿Cómo obtener la información de usuario correspondiente del token? En realidad, hay muy pocas introducciones a esta parte en Internet. Afortunadamente, podemos obtener pistas relevantes directamente de los documentos oficiales. Los documentos oficiales describen la configuración del servidor de recursos de la siguiente manera:
Unas pocas palabras. pero es suficiente para nuestro análisis. Se puede ver en esta configuración que cuando el cliente accede a los recursos protegidos del servidor de recursos, si no se lleva el token, el servidor de recursos devuelve directamente un error 401 no autenticado
Si se lleva el token, el El servidor de recursos utilizará este token para iniciar una solicitud de consulta del usuario al servidor de autenticación. Si el token es incorrecto o ha caducado, se devolverá.
Si la verificación del token es exitosa, el servidor de autenticación devolverá el. información del usuario correspondiente al servidor de recursos En este momento, el marco de seguridad Spring Security del servidor puede controlar los derechos de acceso de acuerdo con el proceso de autorización estándar.
De este proceso podemos ver que un beneficio de la autenticación SSO a través de OAuth2 es el desacoplamiento de la autenticación y la autorización.
Desde la perspectiva de los escenarios de uso diario, la autenticación es más fácil de lograr uniformidad y abstracción. Después de todo, usted es quien es y es quien es dondequiera que vaya. Sin embargo, sus roles en diferentes sistemas pueden variar mucho (usted es el. padre en casa, eres el padre en el trabajo). Eres un empleado y eres hijo de tus padres). Al mismo tiempo, el diseño del personaje está estrechamente relacionado con el diseño del servidor de recursos. No es difícil descubrir en la configuración anterior que si desea obtener roles diseñados para diferentes servidores de recursos, solo necesita reemplazar la configuración /user. Esto brinda mayor flexibilidad a nuestro control de permisos, que son los marcos SSO tradicionales como SAML2. No puedo hacer esto.
Finalmente llegamos a la famosa parte JWT. JWT significa Json Web Token. Recientemente se ha vuelto cada vez más popular con la popularidad de la arquitectura de microservicios y se conoce como una nueva generación de tecnología de autenticación. Hoy veremos cuál es la esencia de jwt.
Primero echemos un vistazo a los puntos débiles de la tecnología de token de OAuth2. Creo que también ha descubierto en la introducción anterior que el mayor problema con la tecnología de token es que no transporta la información del usuario ni el recurso. El servidor no puede realizar la verificación local. Cada vez que se accede a un recurso, el servidor de recursos debe iniciar una solicitud al servidor de autenticación. Una es verificar la validez del token y la otra es obtener la información del usuario correspondiente al token. . Si hay una gran cantidad de solicitudes de este tipo, la eficiencia del procesamiento será indudablemente muy baja y el servidor de autenticación se convertirá en un nodo central, que tiene altos requisitos de SLA y rendimiento de procesamiento, lo cual es muy crítico en una arquitectura distribuida.
JWT nació en este contexto. En esencia, jwt es un token en un formato especial. El oauth2 ordinario emite una cadena hash aleatoria, que en sí misma no tiene sentido, mientras que el token en formato jwt tiene un significado específico y se divide en tres partes:
Estas tres partes están codificadas en base64, entre las cuales Separado por ., un token típico en formato jwt es similar a xxxxx.yyyyy.zzzzz. Instrucciones más específicas sobre el formato jwt no son el tema central de este artículo. Puede ir directamente al sitio web oficial para ver la documentación oficial. No entraré en detalles aquí.
Creo que todo el mundo está familiarizado con las firmas. Sí, jwt no es en realidad una tecnología misteriosa. Al contrario, es muy simple. El servidor de autenticación utiliza la carga útil para generar una firma mediante cifrado simétrico o asimétrico, declara el método de firma en el encabezado y listo. A través de este método esencialmente tradicional, jwt puede realizar la función de verificación de token distribuido, es decir, el servidor de recursos utiliza una clave simétrica o asimétrica mantenida previamente (si es asimétrica, es la clave pública proporcionada por el servidor de autenticación), directamente localmente Token de verificación , este mecanismo de verificación descentralizado es sin duda muy popular en la arquitectura distribuida actual. En comparación con los tokens tradicionales, jwt resuelve los siguientes dos puntos débiles:
En el ejemplo anterior, donde el servidor de recursos y el servidor de autenticación están separados, si el servidor de autenticación emite un token en formato jwt, entonces el servidor de recursos Puede verificar directamente la validez del token y vincular al usuario usted mismo, lo que sin duda mejora en gran medida la eficiencia del procesamiento y reduce los peligros ocultos de un solo punto.
Como dijo Brooks en "El mito del hombre luna": "No existe una solución milagrosa". También existe un malentendido en el uso de JWT. Se cree que los métodos de autenticación tradicionales deberían ser reemplazados por JWT. De hecho, jwt no puede resolver todos los problemas y tiene escenarios aplicables y escenarios inaplicables.
Escenarios aplicables:
Estos escenarios pueden aprovechar al máximo las ventajas de la verificación distribuida y sin estado de jwt
Escenarios no aplicables:
Don No intentes usar jwt para reemplazar la sesión.
En este modo, el mecanismo tradicional de cookies de sesión en realidad funciona mejor. Debido a que jwt no tiene estado y está distribuido, de hecho, siempre que esté dentro del período de validez, el cierre de sesión del usuario no se puede invalidar. , servicio El token del terminal sigue siendo válido. Siempre que utilice este token, aún podrá iniciar sesión en el sistema. Otro problema es el problema de la renovación. El uso de tokens sin duda hará que la renovación sea muy problemática. Por supuesto, también puede usar redis para registrar el estado del token y actualizar este estado después de que el usuario acceda a él, pero esto es para que JWT no tenga estado. estado, y no es necesario considerarlos en el mecanismo tradicional de cookies de sesión. En este escenario, considerando la alta disponibilidad, recomiendo usar un mecanismo de sesión distribuida. Ahora hay muchos marcos maduros para elegir (como la sesión de primavera).