From 066b2be0640b64130ce94ba56738119890d7e9fa Mon Sep 17 00:00:00 2001 From: devfzn Date: Wed, 13 Sep 2023 16:34:41 -0300 Subject: [PATCH] =?UTF-8?q?Spring=20Boot=203=20-=20Buenas=20pr=C3=A1cticas?= =?UTF-8?q?=20y=20protecci=C3=B3n:=20Aula=204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 010_spring_boot/api_rest/api2/pom.xml | 6 + .../controller/AutenticacionController.java | 17 +-- .../api/infra/security/DatosJWTtoken.java | 4 + .../voll/api/infra/security/TokenService.java | 38 +++++++ .../src/main/resources/application.properties | 10 +- 010_spring_boot/spring_boot_2.md | 104 ++++++++++++++++++ 6 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/DatosJWTtoken.java create mode 100644 010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/TokenService.java diff --git a/010_spring_boot/api_rest/api2/pom.xml b/010_spring_boot/api_rest/api2/pom.xml index 058c2f6..cdec0b2 100644 --- a/010_spring_boot/api_rest/api2/pom.xml +++ b/010_spring_boot/api_rest/api2/pom.xml @@ -71,6 +71,12 @@ spring-security-test test + + + com.auth0 + java-jwt + 4.4.0 + diff --git a/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/controller/AutenticacionController.java b/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/controller/AutenticacionController.java index d29d8af..b877e0d 100644 --- a/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/controller/AutenticacionController.java +++ b/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/controller/AutenticacionController.java @@ -2,6 +2,9 @@ package med.voll.api.controller; import jakarta.validation.Valid; import med.voll.api.domain.usuario.DatosAutenticacionUsuario; +import med.voll.api.domain.usuario.Usuario; +import med.voll.api.infra.security.DatosJWTtoken; +import med.voll.api.infra.security.TokenService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; @@ -19,17 +22,17 @@ public class AutenticacionController { @Autowired private AuthenticationManager authenticationManager; + @Autowired + private TokenService tokenService; + @PostMapping public ResponseEntity autenticarUsuario(@RequestBody @Valid DatosAutenticacionUsuario datosAutenticacionUsuario) { - Authentication token = new UsernamePasswordAuthenticationToken( + Authentication authtoken = new UsernamePasswordAuthenticationToken( datosAutenticacionUsuario.login(), datosAutenticacionUsuario.clave()); - authenticationManager.authenticate(token); - //var token = new UsernamePasswordAuthenticationToken( - // datosAutenticacionUsuario.login(), - // datosAutenticacionUsuario.clave()); - //var autentication = authenticationManager.authenticate(token); - return ResponseEntity.ok().build(); + var usuarioAutenticado = authenticationManager.authenticate(authtoken); + var JWTtoken = tokenService.generarToken((Usuario) usuarioAutenticado.getPrincipal()); + return ResponseEntity.ok(new DatosJWTtoken(JWTtoken)); } } diff --git a/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/DatosJWTtoken.java b/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/DatosJWTtoken.java new file mode 100644 index 0000000..f586187 --- /dev/null +++ b/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/DatosJWTtoken.java @@ -0,0 +1,4 @@ +package med.voll.api.infra.security; + +public record DatosJWTtoken(String jwTtoken) { +} diff --git a/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/TokenService.java b/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/TokenService.java new file mode 100644 index 0000000..639c2ff --- /dev/null +++ b/010_spring_boot/api_rest/api2/src/main/java/med/voll/api/infra/security/TokenService.java @@ -0,0 +1,38 @@ +package med.voll.api.infra.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTCreationException; +import med.voll.api.domain.usuario.Usuario; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; + +@Service +public class TokenService { + + @Value("${api.security.secret}") + private String apiSecret; + + public String generarToken(Usuario usuario) { + try { + Algorithm algorithm = Algorithm.HMAC256(apiSecret) ; + return JWT.create() + .withIssuer("voll med") + .withSubject(usuario.getLogin()) + .withClaim("id", usuario.getId()) + .withExpiresAt(generarFechaExpiracion()) + .sign(algorithm); + } catch (JWTCreationException exception){ + throw new RuntimeException(); + } + + } + + private Instant generarFechaExpiracion() { + return LocalDateTime.now().plusHours(2).toInstant(ZoneOffset.of("-03:00")); + } +} diff --git a/010_spring_boot/api_rest/api2/src/main/resources/application.properties b/010_spring_boot/api_rest/api2/src/main/resources/application.properties index e2a71a5..0973600 100644 --- a/010_spring_boot/api_rest/api2/src/main/resources/application.properties +++ b/010_spring_boot/api_rest/api2/src/main/resources/application.properties @@ -1,9 +1,11 @@ # suppress inspection "SpellCheckingInspection" for whole file -spring.datasource.url=jdbc:mysql://192.168.0.8/vollmed_api2 -spring.datasource.username=alura -spring.datasource.password=alura +spring.datasource.url=jdbc:mysql://${DB_URL}/vollmed_api2 +spring.datasource.username=${DB_USER} +spring.datasource.password=${DB_PASS} spring.jpa.show-sql=true spring.jpa.properties.hibernate.format_sql=true -server.error.include-stacktrace=never \ No newline at end of file +server.error.include-stacktrace=never + +api.security.secret=${JWT_SECRET} \ No newline at end of file diff --git a/010_spring_boot/spring_boot_2.md b/010_spring_boot/spring_boot_2.md index a2f4a51..c012aa7 100644 --- a/010_spring_boot/spring_boot_2.md +++ b/010_spring_boot/spring_boot_2.md @@ -564,3 +564,107 @@ create table usuarios( ); ``` +## JSON Web Token + +[JWT](https://jwt.io) - [Repo](https://github.com/auth0/java-jwt) + +Agregar dependencia a [pom.xml](./api_rest/api2/pom.xml) + +```xml + + com.auth0 + java-jwt + 4.4.0 + +``` + +Creación de clase +[TokenService](./api_rest/api2/src/main/java/med/voll/api/infra/security/TokenService.java) +en *package* [infra.security](./api_rest/api2/src/main/java/med/voll/api/infra/security/) + +```java +@Service +public class TokenService { + + @Value("${api.security.secret}") + private String apiSecret; + + public String generarToken(Usuario usuario) { + try { + Algorithm algorithm = Algorithm.HMAC256(apiSecret) ; + return JWT.create() + .withIssuer("voll med") + .withSubject(usuario.getLogin()) + .withClaim("id", usuario.getId()) + .withExpiresAt(generarFechaExpiracion()) + .sign(algorithm); + } catch (JWTCreationException exception){ + throw new RuntimeException(); + } + + } + + private Instant generarFechaExpiracion() { + return LocalDateTime.now() + .plusHours(2) + .toInstant(ZoneOffset.of("-03:00")); + } +} +``` + +Creación de propiedades manejadas por variables de entorno/ambiente + +[application.properties](./api_rest/api2/src/main/resources/application.properties) + +```config +spring.datasource.url=jdbc:mysql://${DB_URL}/vollmed_api2 +spring.datasource.username=${DB_USER} +spring.datasource.password=${DB_PASS} + +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true + +server.error.include-stacktrace=never + +api.security.secret=${JWT_SECRET} +``` + +Creación del DTO +[DatosTokenJWT](./api_rest/api2/src/main/java/med/voll/api/infra/security/DatosJWTtoken.java) +en *package* +[infra.security](./api_rest/api2/src/main/java/med/voll/api/infra/security/) + +```java +public record DatosJWTtoken(String jwTtoken) {} +``` + +Modificación en clase +[AutenticacionController](./api_rest/api2/src/main/java/med/voll/api/controller/AutenticacionController.java) +en *package* [controller](./api_rest/api2/src/main/java/med/voll/api/controller/) + +```java +@RestController +@RequestMapping("/login") +public class AutenticacionController { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private TokenService tokenService; + + @PostMapping + public ResponseEntity autenticarUsuario( + @RequestBody @Valid DatosAutenticacionUsuario datosAutenticacionUsuario) { + Authentication authtoken = new UsernamePasswordAuthenticationToken( + datosAutenticacionUsuario.login(), + datosAutenticacionUsuario.clave()); + var usuarioAutenticado = authenticationManager.authenticate(authtoken); + var JWTtoken = tokenService.generarToken( + (Usuario) usuarioAutenticado.getPrincipal() + ); + return ResponseEntity.ok(new DatosJWTtoken(JWTtoken)); + } +} +``` +