diff --git a/README.md b/README.md index 1678b47..29697e7 100644 --- a/README.md +++ b/README.md @@ -1,671 +1,244 @@ # BaseSetup Spring Security JWT -**BaseSetup** Γ¨ una repository di base per progetti Java Spring Boot, pensata per essere riutilizzata come starter backend con autenticazione JWT, gestione utenti e ruoli, sicurezza avanzata e API documentate. +**BaseSetup** Γ¨ una repository di base per progetti Java Spring Boot, pensata per essere riutilizzata come starter backend robusto, scalabile e sicuro. Include autenticazione JWT, gestione utenti e ruoli, sicurezza avanzata, mapping automatico con MapStruct e documentazione API integrata. ## πŸ“‹ Indice -- [Caratteristiche](#caratteristiche) -- [Architettura JWT](#architettura-jwt) -- [Come funziona il JWT](#come-funziona-il-jwt) -- [UserDetailsImpl e Gestione Utenti](#userdetailsimpl-e-gestione-utenti) -- [Sistema di Ruoli e Autorizzazioni](#sistema-di-ruoli-e-autorizzazioni) -- [Flusso di Autenticazione Completo](#flusso-di-autenticazione-completo) -- [Configurazione Security](#configurazione-security) -- [Endpoints API](#endpoints-api) -- [Quick Start](#quick-start) -- [Configurazione](#configurazione) -- [Estensioni](#estensioni) - -## πŸš€ Caratteristiche - -- **Spring Boot 3.5+** con Maven -- **Autenticazione JWT stateless** completamente configurata -- **Sistema di ruoli gerarchico** (USER, ADMIN, MODERATOR) -- **Registrazione e login sicuri** con validazione -- **Password cifrate con BCrypt** -- **CORS configurato** per sviluppo e produzione -- **Swagger/OpenAPI** per documentazione API -- **Gestione errori strutturata** con risposte JSON -- **Filtri JWT personalizzati** per sicurezza avanzata - -## πŸ” Architettura JWT - -### Componenti Principali +- [Prerequisiti e Tecnologie](#-prerequisiti-e-tecnologie) +- [Struttura del Progetto](#-struttura-del-progetto) +- [Caratteristiche Principali](#-caratteristiche-principali) +- [Architettura di Sicurezza](#-architettura-di-sicurezza) +- [Gestione Dati e Mapping](#-gestione-dati-e-mapping) +- [Configurazione Dettagliata](#-configurazione-dettagliata) +- [API Endpoints e Swagger](#-api-endpoints-e-swagger) +- [Guida all'Avvio](#-guida-allavvio) +- [Troubleshooting](#-troubleshooting) -``` -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ Frontend β”‚ β”‚ AuthController β”‚ β”‚ AuthService β”‚ -β”‚ │───▢│ │───▢│ β”‚ -β”‚ (React/Angular) β”‚ β”‚ /api/auth/* β”‚ β”‚ Business Logic β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - β”‚ β”‚ - β–Ό β–Ό -β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -β”‚ JWT Token β”‚ β”‚ SecurityConfig β”‚ β”‚ UserRepository β”‚ -β”‚ │◀───│ β”‚ β”‚ β”‚ -β”‚ Bearer eyJ0... β”‚ β”‚ Filter Chain β”‚ β”‚ Database Access β”‚ -β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -``` - -### Flusso dei Filtri - -``` -HTTP Request β†’ CORS β†’ AuthTokenFilter β†’ SecurityFilterChain β†’ Controller - ↓ ↓ ↓ - Allow Origins Extract JWT Check Permissions - Validate Token Set Authentication - Set Context Grant/Deny Access -``` - -## 🎯 Come funziona il JWT - -### 1. Generazione del Token - -```java -// JwtUtils.generateJwtToken() -{ - "sub": "username", // Subject (username) - "id": 123, // User ID - "email": "user@example.com", // Email - "firstName": "Mario", // Nome - "lastName": "Rossi", // Cognome - "authorities": [ // Ruoli e permessi - "ROLE_USER", - "ROLE_ADMIN" - ], - "iat": 1640995200, // Issued at - "exp": 1641081600 // Expiration -} -``` +--- -### 2. Struttura del Token JWT +## πŸ›  Prerequisiti e Tecnologie -Un JWT Γ¨ composto da 3 parti separate da punti: +Questo progetto utilizza tecnologie all'avanguardia per garantire performance e manutenibilitΓ . -``` -eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VybmFtZSIsImlkIjoxMjN9.signature -β”‚ β”‚ β”‚ -β”‚ β”‚ └─ Signature (HMAC SHA256) -β”‚ └─ Payload (Base64 encoded JSON) -└─ Header (Base64 encoded) -``` +### Requisiti di Sistema +- **Java Development Kit (JDK) 21**: Assicurati di avere l'ultima versione di Java installata. +- **Maven 3.8+**: Per la gestione delle dipendenze e il build. +- **MySQL 8.0+**: Database relazionale per la persistenza dei dati. -### 3. Validazione e Estrazione - -```java -// Il filtro AuthTokenFilter intercetta ogni richiesta -public class AuthTokenFilter extends OncePerRequestFilter { - - @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, - FilterChain filterChain) { - - // 1. Estrai token dall'header Authorization - String jwt = parseJwt(request); // "Bearer eyJ0..." β†’ "eyJ0..." - - // 2. Valida il token - if (jwt != null && jwtUtils.validateJwtToken(jwt)) { - - // 3. Estrai username e authorities - String username = jwtUtils.getUserNameFromJwtToken(jwt); - Collection authorities = - jwtUtils.getAuthoritiesFromJwtToken(jwt); - - // 4. Crea oggetto Authentication - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(username, null, authorities); - - // 5. Imposta nel SecurityContext - SecurityContextHolder.getContext().setAuthentication(authentication); - } - - filterChain.doFilter(request, response); - } -} -``` +### Stack Tecnologico +| Tecnologia | Versione | Descrizione | +|------------|----------|-------------| +| **Spring Boot** | 3.5.4 | Framework principale | +| **Spring Security** | 6.x | Gestione autenticazione e autorizzazione | +| **Spring Data JPA** | - | ORM e accesso ai dati | +| **JWT (JJWT)** | 0.12.2 | Token standard per autenticazione stateless | +| **MapStruct** | 1.6.3 | Mapping performante tra Entity e DTO | +| **Lombok** | Latest | Riduzione del codice boilerplate | +| **SpringDoc OpenAPI** | 2.8.5 | Documentazione automatica Swagger UI | +| **BCrypt** | - | Hashing sicuro delle password (via Spring Security) | -### 4. Metodi Chiave di JwtUtils - -| Metodo | Descrizione | Utilizzo | -|--------|-------------|----------| -| `generateJwtToken(Authentication)` | Genera JWT dal login | Dopo autenticazione riuscita | -| `generateTokenFromUser(UserDetailsImpl)` | Genera JWT da utente | Per refresh token | -| `validateJwtToken(String)` | Valida firma e scadenza | Ad ogni richiesta protetta | -| `getUserNameFromJwtToken(String)` | Estrae username | Per identificare l'utente | -| `getAuthoritiesFromJwtToken(String)` | Estrae ruoli | Per controllo autorizzazioni | -| `isTokenExpired(String)` | Verifica scadenza | Per gestione refresh | - -## πŸ‘€ UserDetailsImpl e Gestione Utenti - -### UserDetailsImpl: Il Ponte tra Entity e Security - -`UserDetailsImpl` implementa l'interfaccia `UserDetails` di Spring Security e fa da tramite tra la nostra entitΓ  `Utente` e il sistema di autenticazione. - -```java -public class UserDetailsImpl implements UserDetails { - - private Long id; // ID unico dell'utente - private String username; // Username per il login - private String email; // Email (alternativa al username) - private String firstName; // Nome - private String lastName; // Cognome - private String password; // Password cifrata (non esposta in JSON) - - // Flag di stato account Spring Security - private boolean enabled; // Account attivo/disattivato - private boolean accountNonExpired; // Account non scaduto - private boolean accountNonLocked; // Account non bloccato - private boolean credentialsNonExpired; // Credenziali non scadute - - private Collection authorities; // Ruoli e permessi -} -``` - -### Metodo Factory Build - -```java -public static UserDetailsImpl build(Utente user) { - // Converte i ruoli dell'entitΓ  in GrantedAuthority - List authorities = user.getRoles().stream() - .map(role -> new SimpleGrantedAuthority(role.getName())) // "ROLE_USER" - .collect(Collectors.toList()); - - return new UserDetailsImpl( - user.getId(), - user.getUsername(), - user.getEmail(), - user.getFirstName(), - user.getLastName(), - user.getPassword(), - user.getEnabled(), // true/false - user.getAccountNonExpired(), // true/false - user.getAccountNonLocked(), // true/false - user.getCredentialsNonExpired(), // true/false - authorities // Lista di ruoli - ); -} -``` +--- -### UserDetailsServiceImpl: Caricamento Utenti - -```java -@Service -public class UserDetailsServiceImpl implements UserDetailsService { - - @Override - public UserDetails loadUserByUsername(String usernameOrEmail) { - // 1. Cerca utente per username O email - Utente user = userRepository.findByUsernameOrEmail(usernameOrEmail) - .orElseThrow(() -> new UsernameNotFoundException("User not found")); - - // 2. Verifica che l'account sia attivo - if (!user.getEnabled()) { - throw new UsernameNotFoundException("Account disabled"); - } - - // 3. Converte Entity in UserDetails - return UserDetailsImpl.build(user); - } -} +## πŸ“‚ Struttura del Progetto + +Il progetto segue una clean architecture per separare le responsabilitΓ  e facilitare la manutenzione. + +```text +src/main/java/com/giggi/basesetup +β”œβ”€β”€ πŸ“ controller # Gestione delle richieste HTTP (REST API) +β”‚ β”œβ”€β”€ AuthController.java # Login, Registrazione, Refresh Token +β”‚ └── UtenteController.java # CRUD Utenti +β”œβ”€β”€ πŸ“ dto # Data Transfer Objects (Input/Output API) +β”‚ β”œβ”€β”€ πŸ“ request # DTO per richieste in ingresso (es. LoginRequest) +β”‚ └── πŸ“ response # DTO per risposte al client (es. JwtResponse) +β”œβ”€β”€ πŸ“ entity # Modelli di persistenza (JPA Entities) +β”‚ β”œβ”€β”€ Utente.java # Tabella utenti +β”‚ β”œβ”€β”€ Role.java # Tabella ruoli +β”‚ └── RoleName.java # Enum dei ruoli disponibili +β”œβ”€β”€ πŸ“ mapper # Interfacce MapStruct per conversione Entity <-> DTO +β”œβ”€β”€ πŸ“ repository # Interfacce Spring Data JPA per accesso al DB +β”œβ”€β”€ πŸ“ security # Configurazione Core della sicurezza +β”‚ β”œβ”€β”€ SecurityConfig.java # Configurazione FilterChain e Beans +β”‚ β”œβ”€β”€ πŸ“ jwt # Logica JWT (Generazione, Validazione, Filtri) +β”‚ └── πŸ“ service # Implementazione UserDetailsService +β”œβ”€β”€ πŸ“ service # Business Logic +β”‚ β”œβ”€β”€ πŸ“ impl # Implementazione dei servizi +β”‚ └── [Interfaces] # Interfacce dei servizi +└── πŸ“ swagger # Configurazione OpenApi/Swagger ``` -## πŸ›‘οΈ Sistema di Ruoli e Autorizzazioni - -### Gerarchia dei Ruoli - -``` -ROLE_ADMIN - β”œβ”€β”€ PuΓ² fare tutto - β”œβ”€β”€ Gestire tutti gli utenti - β”œβ”€β”€ Creare/eliminare utenti - └── Accesso a tutti gli endpoint - -ROLE_MODERATOR - β”œβ”€β”€ Gestione contenuti - β”œβ”€β”€ Moderazione utenti - └── Endpoint specifici - -ROLE_USER - β”œβ”€β”€ Accesso base - β”œβ”€β”€ Gestione proprio profilo - └── Endpoint pubblici autenticati -``` +--- -### Configurazione Autorizzazioni in SecurityConfig - -```java -.authorizeHttpRequests(auth -> auth - // 🟒 Endpoint PUBBLICI - Nessuna autenticazione - .requestMatchers("/api/auth/**")).permitAll() - .requestMatchers("/swagger-ui/**").permitAll() - .requestMatchers("/actuator/health").permitAll() - - // πŸ”΅ Endpoint per UTENTI AUTENTICATI - .requestMatchers("/api/utentes/**").hasRole("USER") // Solo ROLE_USER+ - - // 🟑 Endpoint per ADMIN - .requestMatchers(HttpMethod.POST, "/api/users").hasRole("ADMIN") - .requestMatchers(HttpMethod.DELETE, "/api/users/**").hasRole("ADMIN") - .requestMatchers(HttpMethod.GET, "/api/users").hasRole("ADMIN") - - // 🟠 Endpoint MISTI - .requestMatchers(HttpMethod.GET, "/api/users/**").authenticated() // Tutti autenticati - .requestMatchers(HttpMethod.PUT, "/api/users/**").authenticated() // Tutti autenticati - - // πŸ”΄ Tutto il resto richiede autenticazione - .anyRequest().authenticated() -) -``` +## πŸš€ Caratteristiche Principali -### Assegnazione Ruoli in Registrazione - -```java -// AuthServiceImpl.registerUser() -Set strRoles = signUpRequest.getRoles(); // ["admin", "user"] -Set roles = new HashSet<>(); - -if (strRoles == null || strRoles.isEmpty()) { - // πŸ”΅ Ruolo DEFAULT - Role userRole = roleRepository.findByName("ROLE_USER") - .orElseThrow(() -> new RuntimeException("Role not found")); - roles.add(userRole); -} else { - strRoles.forEach(role -> { - switch (role.toLowerCase()) { - case "admin": - // 🟑 Admin role - Role adminRole = roleRepository.findByName("ROLE_ADMIN").orElseThrow(); - roles.add(adminRole); - break; - case "mod": - // 🟠 Moderator role - Role modRole = roleRepository.findByName("ROLE_MODERATOR").orElseThrow(); - roles.add(modRole); - break; - default: - // πŸ”΅ Default USER role - Role userRole = roleRepository.findByName("ROLE_USER").orElseThrow(); - roles.add(userRole); - } - }); -} - -user.setRoles(roles); // Assegna i ruoli all'utente -``` +- **Autenticazione Stateless**: Utilizzo di JSON Web Tokens (JWT) per scalabilitΓ  orizzontale. +- **RBAC (Role-Based Access Control)**: Sistema gerarchico di permessi (USER, ADMIN, MODERATOR). +- **Mapping Automatico**: Conversione pulita ed efficiente tra EntitΓ  e DTO grazie a MapStruct. +- **Validazione Dati**: Controlli su input (es. email valida, password robusta) tramite Bean Validation. +- **Sicurezza Avanzata**: + - Password Hashing con **BCrypt**. + - Protezione CORS configurabile. + - Gestione eccezioni di sicurezza centralizzata. +- **Documentazione Live**: Interfaccia Swagger UI per testare le API direttamente dal browser. +- **Actuator**: Endpoint per il monitoraggio dello stato dell'applicazione. -## πŸ”„ Flusso di Autenticazione Completo - -### 1. πŸ“ Registrazione (`POST /api/auth/signup`) - -```mermaid -sequenceDiagram - participant C as Client - participant AC as AuthController - participant AS as AuthService - participant UR as UserRepository - participant RR as RoleRepository - - C->>AC: POST /api/auth/signup - Note over C,AC: {username, email, password, roles} - - AC->>AS: registerUser(RegisterRequest) - - AS->>UR: existsByUsername() - AS->>UR: existsByEmail() - Note over AS: Verifica unicitΓ  - - AS->>AS: passwordEncoder.encode() - Note over AS: Cifra password con BCrypt - - AS->>RR: findByName("ROLE_USER") - Note over AS: Assegna ruoli (default: USER) - - AS->>UR: save(user) - AS->>AC: MessageResponse.success() - AC->>C: 201 Created -``` +--- -### 2. πŸ” Login (`POST /api/auth/signin`) - -```mermaid -sequenceDiagram - participant C as Client - participant AC as AuthController - participant AS as AuthService - participant AM as AuthenticationManager - participant UDS as UserDetailsService - participant JU as JwtUtils - - C->>AC: POST /api/auth/signin - Note over C,AC: {usernameOrEmail, password} - - AC->>AS: authenticateUser(LoginRequest) - - AS->>AM: authenticate(UsernamePasswordAuthenticationToken) - AM->>UDS: loadUserByUsername() - UDS->>UDS: UserDetailsImpl.build(user) - - Note over AM: Verifica password con BCrypt - - AM-->>AS: Authentication object - AS->>JU: generateJwtToken(Authentication) - - Note over JU: Crea JWT con user info + ruoli - - AS->>AC: JwtResponse (token + user info) - AC->>C: 200 OK + JWT Token -``` +## πŸ” Architettura di Sicurezza -### 3. πŸ”’ Richiesta Protetta (`GET /api/users`) - -```mermaid -sequenceDiagram - participant C as Client - participant ATF as AuthTokenFilter - participant JU as JwtUtils - participant SC as SecurityConfig - participant UC as UserController - - C->>ATF: GET /api/users - Note over C,ATF: Authorization: Bearer eyJ0... - - ATF->>JU: getJwtFromHeader() - ATF->>JU: validateJwtToken() - - alt Token valido - ATF->>JU: getUserNameFromJwtToken() - ATF->>JU: getAuthoritiesFromJwtToken() - ATF->>ATF: SecurityContextHolder.setAuthentication() - - ATF->>SC: Verifica autorizzazioni - Note over SC: hasRole("ADMIN") per GET /api/users - - alt Ha ruolo ADMIN - SC->>UC: Processa richiesta - UC->>C: 200 OK + dati utenti - else Non ha ruolo ADMIN - SC->>C: 403 Forbidden - end - - else Token non valido - ATF->>C: 401 Unauthorized - end -``` +### Il Flusso di Autenticazione (JWT) -## βš™οΈ Configurazione Security - -### SecurityConfig - Punti Chiave - -```java -@Configuration -@EnableWebSecurity -@EnableMethodSecurity(prePostEnabled = true) // Abilita @PreAuthorize -public class SecurityConfig { - - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) { - return http - .cors(cors -> cors.configurationSource(corsConfigurationSource())) - .csrf(AbstractHttpConfigurer::disable) // Disabilita CSRF per API REST - .sessionManagement(session -> - session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // JWT = stateless - .exceptionHandling(exception -> - exception.authenticationEntryPoint(unauthorizedHandler)) // Gestione errori 401 - .authorizeHttpRequests(auth -> auth - // Configurazione endpoint... - ) - .addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class) - .build(); - } -} -``` +1. **Login**: L'utente invia credenziali a `/api/auth/signin`. +2. **Verifica**: `AuthenticationManager` valida username e password (confrontando l'hash BCrypt). +3. **Generazione Token**: Se valido, viene generato un JWT firmato contenente: + - **Subject**: Username + - **Claims**: ID, Email, Ruoli + - **Scadenza**: Configurale (default 16 ore) + - **Firma**: HMAC-SHA256 +4. **Utilizzo**: Il client invia il token nell'header `Authorization: Bearer ` per ogni richiesta successiva. +5. **Filtro**: `AuthTokenFilter` intercetta la richiesta, valida il token e imposta il contesto di sicurezza. -### CORS Configuration - -```java -@Bean -public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - - // 🌐 Domini consentiti - configuration.setAllowedOrigins(Arrays.asList( - "http://localhost:3000", // React dev - "http://localhost:4200", // Angular dev - "https://yourdomain.com" // Produzione - )); - - // πŸ“‘ Metodi HTTP consentiti - configuration.setAllowedMethods(Arrays.asList( - "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH" - )); - - // πŸ“‹ Headers consentiti - configuration.setAllowedHeaders(List.of("*")); - - // πŸͺ Consenti credenziali (cookies, auth headers) - configuration.setAllowCredentials(true); - - return source; -} -``` +### Gestione dei Ruoli -## πŸ“‘ Endpoints API +I ruoli sono definiti nell'enum `RoleName` e persistiti nel database. +- **ROLE_USER**: Accesso base. +- **ROLE_MODERATOR**: Accesso a funzionalitΓ  di moderazione. +- **ROLE_ADMIN**: Accesso completo, inclusa gestione utenti (CRUD). -### Autenticazione +L'assegnazione avviene in fase di registrazione o tramite API di amministrazione. -| Endpoint | Metodo | Descrizione | Accesso | Request Body | -|----------|--------|-------------|---------|--------------| -| `/api/auth/signin` | POST | Login utente | 🟒 Pubblico | `LoginRequest` | -| `/api/auth/signup` | POST | Registrazione | 🟒 Pubblico | `RegisterRequest` | +--- -### Gestione Utenti +## πŸ”„ Gestione Dati e Mapping -| Endpoint | Metodo | Descrizione | Accesso | Ruolo Richiesto | -|----------|--------|-------------|---------|-----------------| -| `/api/users` | GET | Lista utenti | 🟑 Protetto | `ROLE_ADMIN` | -| `/api/users` | POST | Crea utente | 🟑 Protetto | `ROLE_ADMIN` | -| `/api/users/{id}` | DELETE | Elimina utente | 🟑 Protetto | `ROLE_ADMIN` | -| `/api/users/{id}` | GET | Dettaglio utente | πŸ”΅ Protetto | Autenticato | -| `/api/users/{id}` | PUT | Aggiorna utente | πŸ”΅ Protetto | Autenticato | -| `/api/utentes/**` | * | Endpoint utenti | πŸ”΅ Protetto | `ROLE_USER` | +Per mantenere pulito il codice, utilizziamo **MapStruct**. Questo evita di esporre le EntitΓ  JPA direttamente nelle API. -### Pubblici +**Esempio di Flusso:** +1. **Controller** riceve `UtenteCreateRequestDTO`. +2. **Service** chiama `UtenteMapper` per convertirlo in `Utente` (Entity). +3. **Repository** salva l'Entity nel DB. +4. **Service** riceve l'Entity salvata e usa `UtenteMapper` per convertirla in `UtenteFindDTO`. +5. **Controller** restituisce il DTO. -| Endpoint | Metodo | Descrizione | Accesso | -|----------|--------|-------------|---------| -| `/swagger-ui.html` | GET | Documentazione API | 🟒 Pubblico | -| `/actuator/health` | GET | Health check | 🟒 Pubblico | +Questo approccio garantisce che password e dati sensibili non vengano mai esposti accidentalmente nelle risposte JSON. -## πŸš€ Quick Start +--- -### 1. Clone e Setup +## βš™οΈ Configurazione Dettagliata -```bash -git clone -cd basesetup -``` - -### 2. Configurazione Database +Il file `src/main/resources/application.properties` Γ¨ il cuore della configurazione. +### Configurazione Server & DB ```properties -# src/main/resources/application.properties - -# Database Configuration -spring.datasource.url=jdbc:mysql://localhost:3306/basesetup_db -spring.datasource.username=your_username -spring.datasource.password=your_password +spring.application.name=BaseSetup +server.port=8080 # Porta del server +server.address=0.0.0.0 # Ascolto su tutte le interfacce -# JWT Configuration -spring.app.jwtSecret=mySecretKey -spring.app.jwtExpirationMs=86400000 +# Connessione Database +spring.datasource.url=jdbc:mysql://localhost:3306/YOUR_DATABASE_NAME +spring.datasource.username=root +spring.datasource.password=rootroot -# JPA Configuration -spring.jpa.hibernate.ddl-auto=update -spring.jpa.show-sql=true +# Configurazione JPA/Hibernate +spring.jpa.show-sql=true # Mostra le query SQL nei log (utile in dev) +spring.jpa.hibernate.ddl-auto=update # Aggiorna lo schema DB automaticamente ``` -### 3. Inserimento Ruoli Iniziali +### Sicurezza & JWT +```properties +# Chiave segreta per la firma dei token (deve essere lunga e complessa) +spring.app.jwtSecret=mySecretKey123912738aopsgjnspkmndfsopkvajoirjg94gf2opfng2moknm -```sql --- Inserisci i ruoli di base -INSERT INTO roles (name) VALUES ('ROLE_USER'); -INSERT INTO roles (name) VALUES ('ROLE_ADMIN'); -INSERT INTO roles (name) VALUES ('ROLE_MODERATOR'); +# Durata del token in millisecondi (es. 57600000 ms = 16 ore) +spring.app.jwtExpirationMs=57600000 ``` -### 4. Avvio Applicazione - -```bash -mvn spring-boot:run +### Upload File (Multipart) +```properties +# Limiti per l'upload di file +spring.servlet.multipart.max-file-size=200MB +spring.servlet.multipart.max-request-size=200MB ``` -### 5. Test con curl - -```bash -# Registrazione -curl -X POST http://localhost:8080/api/auth/signup \ - -H "Content-Type: application/json" \ - -d '{ - "username": "testuser", - "email": "test@example.com", - "password": "password123", - "firstName": "Test", - "lastName": "User", - "roles": ["user"] - }' - -# Login -curl -X POST http://localhost:8080/api/auth/signin \ - -H "Content-Type: application/json" \ - -d '{ - "usernameOrEmail": "testuser", - "password": "password123" - }' - -# Richiesta protetta (sostituisci YOUR_JWT_TOKEN) -curl -X GET http://localhost:8080/api/users/1 \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" +### Logging +Il livello di log Γ¨ configurato per facilitare il debug della sicurezza: +```properties +logging.level.org.springframework.security=DEBUG +logging.level.io.jsonwebtoken=DEBUG ``` -## πŸ”§ Configurazione +--- -### Variabili Environment (Produzione) +## πŸ“‘ API Endpoints e Swagger -```bash -# JWT Secret (generato casualmente) -SPRING_APP_JWT_SECRET=your-256-bit-secret-key-here +Una volta avviata l'applicazione, la documentazione interattiva Γ¨ disponibile a: +πŸ‘‰ **[http://localhost:8080/swagger-ui/index.html](http://localhost:8080/swagger-ui/index.html)** -# Database -SPRING_DATASOURCE_URL=jdbc:mysql://db-host:3306/prod_db -SPRING_DATASOURCE_USERNAME=prod_user -SPRING_DATASOURCE_PASSWORD=secure_password +### Principali Endpoint -# CORS Origins -CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://app.yourdomain.com -``` +| Metodo | Path | Descrizione | Autenticazione | +|--------|------|-------------|----------------| +| `POST` | `/api/auth/signup` | Registrazione nuovo utente | πŸ”“ Pubblico | +| `POST` | `/api/auth/signin` | Login (restituisce JWT) | πŸ”“ Pubblico | +| `GET` | `/api/users` | Lista di tutti gli utenti | πŸ”’ Admin | +| `GET` | `/api/users/{id}` | Dettaglio singolo utente | πŸ”’ Autenticato | +| `PUT` | `/api/users/{id}` | Modifica utente | πŸ”’ Autenticato | +| `DELETE`| `/api/users/{id}`| Eliminazione utente | πŸ”’ Admin | -### Personalizzazione Security +--- -```java -// Per aggiungere nuovi endpoint protetti -.requestMatchers("/api/custom/**").hasRole("CUSTOM_ROLE") +## πŸƒβ€β™‚οΈ Guida all'Avvio -// Per endpoint che richiedono ruoli multipli -.requestMatchers("/api/admin/**").hasAnyRole("ADMIN", "SUPER_ADMIN") +Segui questi passaggi per avviare il progetto in locale. -// Per endpoint con logica custom -.requestMatchers("/api/profile/**").access("@authService.canAccessProfile(authentication, #id)") +### 1. Clona la Repository +```bash +git clone +cd BaseSetup ``` -## πŸ”§ Estensioni +### 2. Configura il Database +Crea un database MySQL vuoto (es. `basesetup_db`) e aggiorna `application.properties` con le tue credenziali. -### 1. Refresh Token +### 3. Build & Run +Puoi avviare l'applicazione usando il wrapper Maven incluso: -```java -// Aggiungi in AuthController -@PostMapping("/refresh") -public ResponseEntity refreshToken(@RequestParam String username) { - JwtResponse response = authService.refreshToken(username); - return ResponseEntity.ok(response); -} +**Linux/Mac:** +```bash +./mvnw spring-boot:run ``` -### 2. Password Reset - -```java -// Nuovo endpoint per reset password -@PostMapping("/forgot-password") -public ResponseEntity forgotPassword(@RequestParam String email) { - // Implementa logica di invio email - return ResponseEntity.ok(MessageResponse.success("Reset email sent")); -} +**Windows:** +```bash +mvnw.cmd spring-boot:run ``` -### 3. Ruoli Personalizzati - -```java -// Aggiungi nuovi ruoli in RoleName enum -public enum RoleName { - ROLE_USER, - ROLE_ADMIN, - ROLE_MODERATOR, - ROLE_PREMIUM_USER, // Nuovo ruolo - ROLE_CONTENT_CREATOR // Nuovo ruolo -} +### 4. Popolazione Iniziale (Opzionale) +Al primo avvio, Hibernate creerΓ  le tabelle. Potrebbe essere necessario inserire manualmente i ruoli se non previsti da uno script di migrazione (es. Flyway) o da un `CommandLineRunner`: +```sql +INSERT INTO roles (name, description) VALUES ('ROLE_USER', 'Standard User'); +INSERT INTO roles (name, description) VALUES ('ROLE_ADMIN', 'Administrator'); +INSERT INTO roles (name, description) VALUES ('ROLE_MODERATOR', 'Moderator'); ``` -### 4. Audit Logging +--- -```java -// Aggiungi listener per tracciare operazioni -@EventListener -public void handleAuthentication(AuthenticationSuccessEvent event) { - log.info("User {} logged in successfully", event.getAuthentication().getName()); -} -``` +## ❓ Troubleshooting ---- +**Problema: "Java version mismatch"** +Assicurati di avere installato Java 21 e che la variabile `JAVA_HOME` punti alla versione corretta. Se usi una versione precedente, aggiorna il tag `` nel `pom.xml`. -## πŸ“š Dipendenze Principali - -```xml - - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - - io.jsonwebtoken - jjwt-api - 0.11.5 - - - - - mysql - mysql-connector-java - - - - - org.projectlombok - lombok - - -``` +**Problema: "Access Denied" (403 Forbidden)** +- Hai incluso il token nell'header? `Authorization: Bearer ` +- Il token Γ¨ scaduto? Controlla il campo `exp` del JWT (puoi decodificarlo su [jwt.io](https://jwt.io)). +- Hai il ruolo corretto? Alcuni endpoint richiedono `ROLE_ADMIN`. + +**Problema: Connessione Database fallita** +- Verifica che il servizio MySQL sia attivo. +- Controlla username, password e URL nel file `application.properties`. +- Verifica che il database specificato nell'URL esista. --- -**πŸŽ‰ Il tuo backend Spring Security con JWT Γ¨ pronto! Sicuro, scalabile e facilmente estendibile per qualsiasi progetto.** \ No newline at end of file +**Happy Coding!** πŸš€ +*Per domande o contributi, apri una Issue o una Pull Request.* diff --git a/pom.xml b/pom.xml index d0f2527..63e82ef 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ - 24 + 21 @@ -63,6 +63,12 @@ runtime + + com.h2database + h2 + test + + io.jsonwebtoken diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 0000000..0d297d7 --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,14 @@ +# Test Configuration using H2 In-Memory Database +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +# Hibernate +spring.jpa.show-sql=true +spring.jpa.hibernate.ddl-auto=create-drop + +# JWT Secret for tests +spring.app.jwtSecret=testSecretKeyForJwtTestingPurposeOnly1234567890 +spring.app.jwtExpirationMs=3600000