auth listo y contador terminados

This commit is contained in:
2025-09-10 17:36:04 -04:00
commit bdefcf5162
21 changed files with 1090 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package com.example.fercoganbackend;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FercoganbackendApplication {
public static void main(String[] args) {
SpringApplication.run(FercoganbackendApplication.class, args);
}
}

View File

@@ -0,0 +1,34 @@
package com.example.fercoganbackend.component;
// ContadorWebSocketHandler.java
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
public class ContadorWebSocketHandler extends TextWebSocketHandler {
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
}
public void broadcast(String message) {
for (WebSocketSession session : sessions) {
try {
session.sendMessage(new TextMessage(message));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,55 @@
package com.example.fercoganbackend.configuration;
import com.example.fercoganbackend.service.UsuarioDetailsService;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
private final UsuarioDetailsService usuarioDetailsService;
public SecurityConfig(UsuarioDetailsService usuarioDetailsService) {
this.usuarioDetailsService = usuarioDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/**").permitAll()
.requestMatchers("/admin/**").hasAnyAuthority("SUPER_USUARIO","ADMIN")
.anyRequest().authenticated()
)
.httpBasic(httpBasic -> httpBasic
.authenticationEntryPoint((request, response, authException) -> {
// Log del fallo de autenticación
System.out.println("Fallo de autenticación: " + authException.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
})
);
return http.build();
}
}

View File

@@ -0,0 +1,21 @@
package com.example.fercoganbackend.configuration;
// WebSocketConfig.java
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.*;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final ContadorWebSocketHandler handler;
public WebSocketConfig(ContadorWebSocketHandler handler) {
this.handler = handler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(handler, "/ws/contador").setAllowedOrigins("*");
}
}

View File

@@ -0,0 +1,55 @@
package com.example.fercoganbackend.controller;
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
import com.example.fercoganbackend.entity.Rol;
import com.example.fercoganbackend.entity.Usuario;
import com.example.fercoganbackend.service.ContadorService;
import com.example.fercoganbackend.service.UsuarioService;
import org.springframework.web.bind.annotation.*;
import java.util.Set;
import java.util.List;
@RestController
public class AppController {
private final UsuarioService usuarioService;
private final ContadorService contadorService;
private final ContadorWebSocketHandler webSocketHandler;
public AppController(UsuarioService usuarioService, ContadorService contadorService, ContadorWebSocketHandler webSocketHandler) {
this.usuarioService = usuarioService;
this.contadorService = contadorService;
this.webSocketHandler = webSocketHandler;
}
// Registro
@PostMapping("/auth/registrar")
public String registrar(@RequestParam String username,
@RequestParam String password,
@RequestParam Set<Rol> roles) {
usuarioService.registrarUsuario(username, password, roles);
return "Usuario registrado, pendiente de aprobación";
}
// Verificar si aprobado
@GetMapping("/auth/verificar/{username}")
public String verificar(@PathVariable String username) {
boolean aprobado = usuarioService.estaAprobado(username);
return aprobado ? "Usuario aprobado ✅" : "Usuario pendiente ❌";
}
// Listar pendientes (solo admin/super)
@GetMapping("/admin/pendientes")
public List<Usuario> pendientes() {
return usuarioService.listarPendientes();
}
// Aceptar usuario (solo admin/super)
@PostMapping("/admin/aceptar/{id}")
public String aceptar(@PathVariable Long id) {
usuarioService.aceptarUsuario(id);
return "Usuario aprobado ✅";
}
}

View File

@@ -0,0 +1,30 @@
package com.example.fercoganbackend.controller;
// ContadorController.java (REST API)
import com.example.fercoganbackend.component.ContadorWebSocketHandler;
import com.example.fercoganbackend.service.ContadorService;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/contador")
public class ContadorController {
private final ContadorService contadorService;
private final ContadorWebSocketHandler webSocketHandler;
public ContadorController(ContadorService contadorService, ContadorWebSocketHandler webSocketHandler) {
this.contadorService = contadorService;
this.webSocketHandler = webSocketHandler;
}
@PostMapping("/incrementar")
public int incrementar() {
int nuevoValor = contadorService.incrementar();
webSocketHandler.broadcast(String.valueOf(nuevoValor));
return nuevoValor;
}
@GetMapping
public int getContador() {
return contadorService.getContador();
}
}

View File

@@ -0,0 +1,6 @@
package com.example.fercoganbackend.entity;
public enum Rol {
SUPER_USUARIO, ADMIN, COLABORADOR, CLIENTE
}

View File

@@ -0,0 +1,67 @@
package com.example.fercoganbackend.entity;
import jakarta.persistence.*;
import java.util.Set;
@Entity
public class Usuario {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@Column(nullable = false)
private Boolean aprobado = false;
@ElementCollection(fetch = FetchType.EAGER)
@Enumerated(EnumType.STRING)
private Set<Rol> roles; // aquí consumes el enum
// getters y setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isAprobado() {
return aprobado;
}
public void setAprobado(boolean aprobado) {
this.aprobado = aprobado;
}
public Set<Rol> getRoles() {
return roles;
}
public void setRoles(Set<Rol> roles) {
this.roles = roles;
}
}

View File

@@ -0,0 +1,54 @@
package com.example.fercoganbackend.otros;
import com.example.fercoganbackend.entity.Usuario;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.stream.Collectors;
public class UsuarioPrincipal implements UserDetails {
private final Usuario usuario;
public UsuarioPrincipal(Usuario usuario) {
this.usuario = usuario;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return usuario.getRoles().stream()
.map(r -> new SimpleGrantedAuthority("ROLE_" + r.name()))
.collect(Collectors.toList());
}
@Override
public String getPassword() {
return usuario.getPassword();
}
@Override
public String getUsername() {
return usuario.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return usuario.isAprobado(); // aquí usamos tu booleano
}
}

View File

@@ -0,0 +1,9 @@
package com.example.fercoganbackend.repository;
import com.example.fercoganbackend.entity.Usuario;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {
Optional<Usuario> findByUsername(String username);
}

View File

@@ -0,0 +1,33 @@
package com.example.fercoganbackend.service;
// ContadorService.java
import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class ContadorService {
private final AtomicInteger contador = new AtomicInteger(200);
private boolean sw = true;
public int incrementar() {
int valorActual = contador.get();
int incremento;
if (valorActual < 300) {
incremento = sw ? 20 : 30;
sw = !sw; // alterna el booleano
} else if (valorActual < 1000) {
incremento = 50;
} else if (valorActual < 2000) {
incremento = 100;
} else {
incremento = 500;
}
return contador.getAndAdd(incremento);
}
public int getContador() {
return contador.get();
}
}

View File

@@ -0,0 +1,47 @@
package com.example.fercoganbackend.service;
import com.example.fercoganbackend.entity.Usuario;
import com.example.fercoganbackend.otros.UsuarioPrincipal;
import com.example.fercoganbackend.repository.UsuarioRepository;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
public class UsuarioDetailsService implements UserDetailsService {
private final UsuarioRepository usuarioRepository;
private final Logger logger = LoggerFactory.getLogger(UsuarioDetailsService.class);
public UsuarioDetailsService(UsuarioRepository usuarioRepository) {
this.usuarioRepository = usuarioRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.info("Intentando autenticar usuario: {}", username);
Usuario usuario = usuarioRepository.findByUsername(username)
.orElseThrow(() -> {
logger.warn("Usuario no encontrado: {}", username);
return new UsernameNotFoundException("Usuario no encontrado");
});
logger.info("Usuario encontrado: {}, aprobado: {}", usuario.getUsername(), usuario.isAprobado());
logger.info("Roles del usuario: {}", usuario.getRoles());
return new org.springframework.security.core.userdetails.User(
usuario.getUsername(),
usuario.getPassword(),
usuario.isAprobado(), true, true, true,
usuario.getRoles().stream()
.map(r -> new SimpleGrantedAuthority(r.name()))
.toList()
);
}
}

View File

@@ -0,0 +1,42 @@
package com.example.fercoganbackend.service;
import com.example.fercoganbackend.entity.Rol;
import com.example.fercoganbackend.entity.Usuario;
import com.example.fercoganbackend.repository.UsuarioRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
@Service
public class UsuarioService {
private final UsuarioRepository repo;
private final PasswordEncoder encoder;
public UsuarioService(UsuarioRepository repo, PasswordEncoder encoder) {
this.repo = repo;
this.encoder = encoder;
}
public Usuario registrarUsuario(String username, String password, Set<Rol> roles) {
Usuario u = new Usuario();
u.setUsername(username);
u.setPassword(encoder.encode(password));
u.setRoles(roles);
u.setAprobado(false); // no aprobado hasta aceptación
return repo.save(u);
}
public List<Usuario> listarPendientes() {
return repo.findAll().stream().filter(u -> !u.isAprobado()).toList();
}
public Usuario aceptarUsuario(Long id) {
Usuario u = repo.findById(id).orElseThrow();
u.setAprobado(true);
return repo.save(u);
}
public boolean estaAprobado(String username) {
return repo.findByUsername(username).map(Usuario::isAprobado).orElse(false);
}
}