Spring Boot 3 - Buenas prácticas y protección: Aula 4

This commit is contained in:
devfzn 2023-09-13 16:34:41 -03:00
parent d2d56e2a91
commit 066b2be064
Signed by: devfzn
GPG Key ID: E070ECF4A754FDB1
6 changed files with 168 additions and 11 deletions

View File

@ -71,6 +71,12 @@
<artifactId>spring-security-test</artifactId> <artifactId>spring-security-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -2,6 +2,9 @@ package med.voll.api.controller;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import med.voll.api.domain.usuario.DatosAutenticacionUsuario; 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.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
@ -19,17 +22,17 @@ public class AutenticacionController {
@Autowired @Autowired
private AuthenticationManager authenticationManager; private AuthenticationManager authenticationManager;
@Autowired
private TokenService tokenService;
@PostMapping @PostMapping
public ResponseEntity autenticarUsuario(@RequestBody @Valid DatosAutenticacionUsuario datosAutenticacionUsuario) { public ResponseEntity autenticarUsuario(@RequestBody @Valid DatosAutenticacionUsuario datosAutenticacionUsuario) {
Authentication token = new UsernamePasswordAuthenticationToken( Authentication authtoken = new UsernamePasswordAuthenticationToken(
datosAutenticacionUsuario.login(), datosAutenticacionUsuario.login(),
datosAutenticacionUsuario.clave()); datosAutenticacionUsuario.clave());
authenticationManager.authenticate(token); var usuarioAutenticado = authenticationManager.authenticate(authtoken);
//var token = new UsernamePasswordAuthenticationToken( var JWTtoken = tokenService.generarToken((Usuario) usuarioAutenticado.getPrincipal());
// datosAutenticacionUsuario.login(), return ResponseEntity.ok(new DatosJWTtoken(JWTtoken));
// datosAutenticacionUsuario.clave());
//var autentication = authenticationManager.authenticate(token);
return ResponseEntity.ok().build();
} }
} }

View File

@ -0,0 +1,4 @@
package med.voll.api.infra.security;
public record DatosJWTtoken(String jwTtoken) {
}

View File

@ -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"));
}
}

View File

@ -1,9 +1,11 @@
# suppress inspection "SpellCheckingInspection" for whole file # suppress inspection "SpellCheckingInspection" for whole file
spring.datasource.url=jdbc:mysql://192.168.0.8/vollmed_api2 spring.datasource.url=jdbc:mysql://${DB_URL}/vollmed_api2
spring.datasource.username=alura spring.datasource.username=${DB_USER}
spring.datasource.password=alura spring.datasource.password=${DB_PASS}
spring.jpa.show-sql=true spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true spring.jpa.properties.hibernate.format_sql=true
server.error.include-stacktrace=never server.error.include-stacktrace=never
api.security.secret=${JWT_SECRET}

View File

@ -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
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
```
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));
}
}
```