JWT de inicio de sesión único con Spring Security OAuth
El uso de JWT de Spring Security OAuth2 evita la necesidad de enviar de forma remota el servicio de autorización de autenticación para cada solicitud. El servidor de recursos se autentica solo una vez desde el servidor de autorización y devuelve un JWT que contiene toda la información del usuario, incluida la información de permisos.
1. ¿Qué es JWT?
JSON Web Token (JWT) es un estándar abierto (RFC 7519) que define un estándar compacto y autónomo para que la información se empaquete en objetos JSON. La información del sujeto se cifra y se verifica mediante firmas digitales. Los JWT normalmente se firman utilizando el algoritmo HMAC o el algoritmo RSA (cifrado asimétrico de clave pública/privada), que es altamente seguro.
2. La estructura de JWT
La estructura de JWT consta de tres partes: encabezado, carga útil y firma. Por lo tanto, el formato habitual de JWT es xxxxx.yyyyy.zzzzzz
2.1 Encabezado
El encabezado generalmente consta de dos partes: el tipo de token (es decir, JWT) y el tipo. del algoritmo utilizado. Por ejemplo: HMAC, SHA256 y RSA.
Para situaciones en las que se coloca información confidencial en el encabezado del JWT, no se recomienda codificar Base64 el encabezado como la primera parte del JWT.
2.2. Carga útil
El siguiente es un ejemplo de la parte de carga útil:
La carga útil codificada en Base64 es la segunda parte del JWT y no se recomienda su uso. colocado en la carga útil del JWT. No se recomienda colocar información confidencial en la carga útil de JWT.
2.3. Firma
Para crear la parte de la firma, el encabezado y la carga codificados en Base64 deben cifrarse utilizando una clave secreta. El algoritmo de cifrado es el siguiente:
La firma se puede utilizar como segunda parte del JWT. Las firmas se pueden utilizar para verificar que un mensaje no haya sido alterado durante la entrega. Para los tokens firmados con una clave privada, también puede verificar que el remitente del JWT es quien dice ser.
3. Cómo funciona JWT
Una vez que el cliente obtiene el JWT, para cada solicitud posterior, no es necesario pasar por el servicio de autorización para determinar el usuario solicitante y los permisos del usuario. . En los sistemas de microservicios, JWT se puede utilizar para implementar el inicio de sesión único. El diagrama de flujo de autenticación es el siguiente:
4. Estructura del proyecto de caso
El diagrama del proyecto es el siguiente:
5. Construir un servicio de autorización de servicio de autenticación
UserServiceDetail.java
UserRepository.java
La clase de entidad Usuario es la misma que en el artículo anterior. Como en el artículo anterior, la clase de entidad Usuario necesita implementar la interfaz UserDetails y la clase de entidad Rol necesita implementar la interfaz GrantedAuthority.
User.java
Role.java
Debe utilizar la utilidad Java keytool para generar el archivo jks y garantizar que las variables de entorno de Java sean normales. Ingrese el comando de la siguiente manera:
p>
La opción -alias se usa para alias, -keyalg se usa para keyalg y -keyalg se usa para keyalg. keyalg es el algoritmo de cifrado, -keypass y -storepass son opciones de contraseña, -keystore es el nombre del archivo jks y -validity configura el tiempo de caducidad del archivo jks.
El archivo jks generado servirá como una clave privada, que solo podrán conservar los servicios autorizados y se utilizará para el cifrado para generar JWT.
Para servicios de recursos, como servicios de usuario, debe utilizar la clave pública de jks para descifrar el JWT. El comando para obtener la clave pública del archivo jks es el siguiente:
Este comando requiere que instale la dirección de descarga de openSSL y luego configure manualmente el directorio donde se encuentra el openssl.exe instalado como entorno. variable.
Después de ingresar la contraseña fzp123, se mostrará mucha información. Solo es necesario extraer la clave pública, de la siguiente manera:
Cree un nuevo archivo public.cert y cópielo. información de clave pública anterior al archivo public.cert y guárdelo. Luego coloque este archivo en el directorio src/main/resources del servicio de recursos (como servicio de usuario). El servicio de autenticación ya está creado.
Maven puede compilar el archivo jks al compilar el proyecto, lo que provoca que el archivo jks sea confuso y, en última instancia, no pueda ejecutarse. Debe agregar el siguiente contenido al archivo pom.xml:
6. Cree el servicio de recursos de servicio de usuario
Inyecte un Bean de tipo JwtTokenStore, inicialice el convertidor JWT JwtAccessTokenConverter y configúrelo para La clave pública para descifrar el JWT.
Configurar la gestión de autenticación para los servicios de recursos Además del registro y el inicio de sesión, todas las interfaces requieren autenticación.
Cree una nueva clase de configuración GlobalMethodSecurityConfig y utilice la anotación @EnableGlobalMethodSecurity para habilitar la verificación de seguridad a nivel de método.
Copie las clases Usuario, Rol y UserRepository del módulo de servicio de autenticación a este módulo. Escriba un método para insertar usuarios en el UserService de la capa de servicio. El código es el siguiente:
Configure la clase de herramienta BPwdEncoderUtil para cifrar las contraseñas de los usuarios:
Implemente una interfaz API de registro de usuarios. / usuario/registro, el código es el siguiente:
Agregue el método login() en UserServiceDetail de la capa de servicio, el código es el siguiente:
AuthServiceClient actúa como un disfraz cliente, al enviar la solicitud del cliente de servicio de autenticación, el cliente de servicio de autenticación podrá cifrar la contraseña del usuario. AuthServiceClient actúa como un cliente Feign para llamar de forma remota a la interfaz de servicio de autenticación /oauth/token para obtener JWT. En la interfaz API que solicita /oauth/token, debe pasar la información de autorización, el tipo de autenticación (grant_type), el nombre de usuario y la contraseña en el encabezado de solicitud. El código es el siguiente:
Donde está AuthServiceHystrix. el fusible de AuthServiceClient.
El código es el siguiente:
El JWT contiene información sobre access_token, token_type y refresco_token, el código es el siguiente:
UserLoginDTO contiene las propiedades del miembro JWT del usuario y la entidad que devuelve los datos:
Clase de excepción de inicio de sesión UserLoginException
Clase de conmutación de manejo de excepciones global ExceptionHandle
Agregue una nueva interfaz API de inicio de sesión /user/login en la clase UserController de la capa web, como se muestra a continuación:
Inicie eureka-service, auth-service y user-service en secuencia.
7. Pruebas con Postman
Acceso denegado por falta de permisos. Agregue manualmente permisos ROLE_ADMIN en la base de datos y asócielos con el usuario. Vuelva a iniciar sesión y obtenga el JWT, luego solicite acceso a la interfaz /user/foo nuevamente.
En este caso, el usuario utiliza la interfaz de inicio de sesión para obtener el JWT cifrado por el servicio de autorización. Después de obtener con éxito el JWT, el usuario debe llevar el JWT cada vez que solicite posteriormente el servicio de recursos. fuerte> El servicio de recursos utiliza la clave pública para descifrar el JWT. Después de un descifrado exitoso, se puede obtener la información del usuario y la información de permiso para determinar a qué usuario corresponde el reportero y puede ser utilizado por el reportero. fuerte>Usuario y permisos correspondientes a JWT.
Al obtener un token una vez y usarlo varias veces, el servicio de recursos ya no utilizará la información del usuario correspondiente al token y los permisos del usuario para acceder al servicio de autorización cada vez.
Si la información del usuario o la información de permiso cambia, la información almacenada en el token no cambiará y deberá iniciar sesión nuevamente para recuperar el nuevo token. Incluso si se recupera el token, aún se puede utilizar si el token original no ha caducado. Una mejora sería almacenar en caché el token adquirido en la puerta de enlace después de un inicio de sesión exitoso. Si los permisos del usuario cambian, se eliminará el token almacenado en caché en la puerta de enlace. Cuando la solicitud pasa por la puerta de enlace, determina si el token solicitado está presente en la memoria caché y, en caso contrario, solicita al usuario que inicie sesión nuevamente.