diff --git a/pom.xml b/pom.xml
index deb06a4..4ecf269 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
com.app
User-Api-Jwt
- 1.1.0
+ 1.1.1
User-Api-Jwt
Proyecto de muestra sobre cómo implementar la seguridad con
JWT basada en Spring boot 3 y Spring security 6
diff --git a/src/main/java/com/app/UserApiJwtApplication.java b/src/main/java/com/app/UserApiJwtApplication.java
index 15fa4bf..f038aa7 100644
--- a/src/main/java/com/app/UserApiJwtApplication.java
+++ b/src/main/java/com/app/UserApiJwtApplication.java
@@ -5,6 +5,7 @@
import com.app.model.UserEntity;
import com.app.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -20,17 +21,22 @@ public class UserApiJwtApplication {
@Autowired
UserRepository userRepository;
+ @Value("${user.admin.username}")
+ String usernameAdmin;
+ @Value("${user.admin.password}")
+ String passwordAdmin;
+
public static void main(String[] args) {
SpringApplication.run(UserApiJwtApplication.class, args);
}
-/* @Bean
+@Bean
CommandLineRunner init() {
return args -> {
UserEntity userEntity = UserEntity.builder()
- .username("marco")
- .password(passwordEncoder.encode("1234"))
+ .username(usernameAdmin)
+ .password(passwordEncoder.encode(passwordAdmin))
.roles(Set.of(RoleEntity.builder()
.name(ERole.valueOf(ERole.ADMIN.name()))
.build()))
@@ -38,5 +44,5 @@ CommandLineRunner init() {
userRepository.save(userEntity);
};
- }*/
+ }
}
diff --git a/src/main/java/com/app/controller/AdminController.java b/src/main/java/com/app/controller/AdminController.java
index 176fc6e..6234c0e 100644
--- a/src/main/java/com/app/controller/AdminController.java
+++ b/src/main/java/com/app/controller/AdminController.java
@@ -1,14 +1,26 @@
package com.app.controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.app.dto.RegisterDTO;
+import com.app.service.UserEntityService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Set;
@RestController
@RequestMapping("private")
public class AdminController {
- @GetMapping("/")
- public String hola(){
- return "Hola admin";
+ @Autowired
+ UserEntityService userEntityService;
+
+ //Endpoint para poder registrarse y tener acceso como admin
+ @PostMapping("/auth/register")
+ public ResponseEntity> register(@RequestBody RegisterDTO registerDTO) {
+ RegisterDTO user = registerDTO;
+ user.getRoles().clear();
+ user.setRoles(Set.of("ADMIN","USER"));
+ return ResponseEntity.status(HttpStatus.OK).body(userEntityService.registerUser(registerDTO));
}
}
diff --git a/src/main/java/com/app/controller/AuthController.java b/src/main/java/com/app/controller/AuthController.java
deleted file mode 100644
index 0dfc3f3..0000000
--- a/src/main/java/com/app/controller/AuthController.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.app.controller;
-
-import com.app.dto.RegisterDTO;
-import com.app.service.RegisterService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping("auth")
-public class AuthController {
- @Autowired
- RegisterService registerService;
- //Endpoint para poder registrarse y tener acceso
- @PostMapping("/register")
- public ResponseEntity> register(@RequestBody RegisterDTO registerDTO){
- return ResponseEntity.status(HttpStatus.OK).body(registerService.registerUser(registerDTO));
- }
-}
diff --git a/src/main/java/com/app/controller/Controller.java b/src/main/java/com/app/controller/Controller.java
index ab301c1..8cda2cc 100644
--- a/src/main/java/com/app/controller/Controller.java
+++ b/src/main/java/com/app/controller/Controller.java
@@ -1,14 +1,25 @@
package com.app.controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.app.dto.RegisterDTO;
+import com.app.service.UserEntityService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Set;
@RestController
@RequestMapping("public")
public class Controller {
- @GetMapping("/")
- public String hola(){
- return "Hola";
+ @Autowired
+ UserEntityService userEntityService;
+ //Endpoint para poder registrarse y tener acceso
+ @PostMapping("/auth/register")
+ public ResponseEntity> register(@RequestBody RegisterDTO registerDTO){
+ RegisterDTO user = registerDTO;
+ user.getRoles().clear();
+ user.setRoles(Set.of("USER"));
+ return ResponseEntity.status(HttpStatus.OK).body(userEntityService.registerUser(registerDTO));
}
}
diff --git a/src/main/java/com/app/dto/RegisterDTO.java b/src/main/java/com/app/dto/RegisterDTO.java
index e6f8da2..2f93ccb 100644
--- a/src/main/java/com/app/dto/RegisterDTO.java
+++ b/src/main/java/com/app/dto/RegisterDTO.java
@@ -2,10 +2,13 @@
import lombok.Builder;
import lombok.Getter;
+import lombok.Setter;
+
import java.util.Set;
@Builder
@Getter
+@Setter
public class RegisterDTO {
private String username;
private String password;
diff --git a/src/main/java/com/app/model/UserEntity.java b/src/main/java/com/app/model/UserEntity.java
index edf5110..f1a70f0 100644
--- a/src/main/java/com/app/model/UserEntity.java
+++ b/src/main/java/com/app/model/UserEntity.java
@@ -1,19 +1,25 @@
package com.app.model;
+import jakarta.annotation.Nullable;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
-
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import java.util.Collection;
import java.util.Set;
+import java.util.stream.Collectors;
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
-public class UserEntity{
+public class UserEntity implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@@ -24,4 +30,32 @@ public class UserEntity{
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set roles;
+
+ //Obtención de autoridades del usuario
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return roles
+ .stream()
+ .map(role->new SimpleGrantedAuthority("ROLE_".concat(role.getName().name())))
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
}
diff --git a/src/main/java/com/app/security/SecurityConfig.java b/src/main/java/com/app/security/SecurityConfig.java
index b0dbbf3..03e5950 100644
--- a/src/main/java/com/app/security/SecurityConfig.java
+++ b/src/main/java/com/app/security/SecurityConfig.java
@@ -57,7 +57,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager
//es creado dentro de esta clase
jwtAuthenticationFilter.setAuthenticationManager(authenticationManager);
//Se configura el endpoint para autenticarse
- jwtAuthenticationFilter.setFilterProcessesUrl("/auth/login");
+ jwtAuthenticationFilter.setFilterProcessesUrl("/public/auth/login");
return http
// Se deshabilita Cross-site request forgery
@@ -69,13 +69,13 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager
.authorizeHttpRequests(
//Configuración de acceso a los endpoints
auth-> {
- //endpoint para registrarse permitido para todos
- auth.requestMatchers("/auth/register").permitAll();
+ //endpoint para poder registrarse por primera vez
+ auth.requestMatchers("/public/auth/register").permitAll();
//endpoint público con acceso para usuarios y administradores
auth.requestMatchers("/public/**").hasAnyRole("USER","ADMIN");
//endpoint privado con acceso solo para administradores
auth.requestMatchers("/private/**").hasRole("ADMIN");
- //para demas endpint solo se debe estar autenticado
+ //para demas endpoint solo se debe estar autenticado
auth.anyRequest().authenticated();
}
)
diff --git a/src/main/java/com/app/service/UserDetailsServiceImpl.java b/src/main/java/com/app/service/UserDetailsServiceImpl.java
index fdf5fb0..f942a1a 100644
--- a/src/main/java/com/app/service/UserDetailsServiceImpl.java
+++ b/src/main/java/com/app/service/UserDetailsServiceImpl.java
@@ -3,21 +3,18 @@
import com.app.model.UserEntity;
import com.app.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
-import java.util.Collection;
-import java.util.stream.Collectors;
//Esta clase sirve para retornar un usuario el cual es de tipo User de Spring Security
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
- UserRepository userRepository;
+ private UserRepository userRepository;
+ private UserEntityService userEntityService = new UserEntityServiceImpl();
+
// Método para cargar un usuario con todos sus datos por medio de sus username
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -27,25 +24,7 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx
UserEntity user = userRepository
.findByUsername(username)
.orElseThrow(()->new UsernameNotFoundException("User not found"));
- //Colleccion la cual contiene el tipo o tipos de autoridad que tiene el usuario
- Collection extends GrantedAuthority> authorities = user
- //Obtención de roles y mapeo de roles
- .getRoles()
- .stream().
- /*Cada rol es guardado en un objeto de tipo SimpleGrantedAuthority con el nombre de "ROLE_" y
- se le concatena el rol del usuario*/
- map(role->new SimpleGrantedAuthority("ROLE_".concat(role.getName().name())))
- //Finalmente se convierte todo en una colleccion de objetos SimpleGrantedAuthority los cuales son los roles
- .collect(Collectors.toSet());
// Se devuelve un usuario de tipo User (No de tipo UserEntity) esta clase de es de Spring Security
- return new User(
- user.getUsername(),//Usernmae del usuario
- user.getPassword(),//Contraseña del usuario
- true,//Usuario activo
- true,//La cuenta no expira
- true,//Las credenciales no expiran
- true,//La cuenta no se bloquea
- authorities//Roles del usuario
- );
+ return userEntityService.createUserSecurity(user);
}
}
diff --git a/src/main/java/com/app/service/UserEntityService.java b/src/main/java/com/app/service/UserEntityService.java
new file mode 100644
index 0000000..ea53f09
--- /dev/null
+++ b/src/main/java/com/app/service/UserEntityService.java
@@ -0,0 +1,10 @@
+package com.app.service;
+
+import com.app.dto.RegisterDTO;
+import com.app.model.UserEntity;
+import org.springframework.security.core.userdetails.User;
+
+public interface UserEntityService {
+ public UserEntity registerUser(RegisterDTO registerDTO);
+ public User createUserSecurity(UserEntity userEntity);
+}
diff --git a/src/main/java/com/app/service/RegisterService.java b/src/main/java/com/app/service/UserEntityServiceImpl.java
similarity index 71%
rename from src/main/java/com/app/service/RegisterService.java
rename to src/main/java/com/app/service/UserEntityServiceImpl.java
index f367e8e..1536c6c 100644
--- a/src/main/java/com/app/service/RegisterService.java
+++ b/src/main/java/com/app/service/UserEntityServiceImpl.java
@@ -6,20 +6,20 @@
import com.app.model.UserEntity;
import com.app.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
-
import java.util.Set;
import java.util.stream.Collectors;
@Service
-public class RegisterService {
+public class UserEntityServiceImpl implements UserEntityService{
@Autowired
UserRepository userRepository;
@Autowired
PasswordEncoder passwordEncoder;
+ //Método para registrar un usuario nuevo
public UserEntity registerUser(RegisterDTO registerDTO){
-
Set roles =
//obtención de roles
registerDTO.getRoles()
@@ -40,4 +40,17 @@ public UserEntity registerUser(RegisterDTO registerDTO){
return userRepository.save(userEntity);
}
+
+ //Método para la creación de un usuario de seguridad de Spring
+ public User createUserSecurity(UserEntity userEntity){
+ return new User(
+ userEntity.getUsername(),
+ userEntity.getPassword(),
+ true,
+ true,
+ true,
+ true,
+ userEntity.getAuthorities()
+ );
+ }
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 4246cd0..ebbaec1 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -3,6 +3,10 @@ spring:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
+user:
+ admin:
+ username: ${USER_ADMIN_USERNAME}
+ password: ${USER_ADMIN_PASSWORD}
jpa:
hibernate:
ddl-auto: ${SPRING_JPA_HIBERNATE_DDL_AUTO}