✅ Step 1: Create a Standard Response Wrapper
package com.bankapp.payload;
public class ApiResponse<T> {
private String message;
private T data;
public ApiResponse() {
}
public ApiResponse(String message, T data) {
this.message = message;
this.data = data;
}
// Getters and setters
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
We now update each controller method to wrap the response using ApiResponse.
🛠 Example Fix: AccountController.java
🔁 Apply These Changes Across All Controllers:
----------- AUTHENTICATION THINGS ---------------
✅ Step 1: DTOs for Signup & Login
package com.bankapp.payload;
public class SignupRequest {
private String name;
private String email;
private String password;
private String confirmPassword;
// Getters and Setters
}
package com.bankapp.payload;
public class LoginRequest {
private String email;
private String password;
// Getters and Setters
}
✅ Step 2: Password Hashing (Using Spring Security's BCrypt)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Add PasswordEncoder bean
In a config file (AppConfig.java):
package com.bankapp.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class AppConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
✅ Step 3: Signup and Login Logic in AuthController
package com.bankapp.controller;
import com.bankapp.model.User;
import com.bankapp.payload.ApiResponse;
import com.bankapp.payload.LoginRequest;
import com.bankapp.payload.SignupRequest;
import com.bankapp.repository.UserRepository;
import com.bankapp.security.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private AuthenticationManager authenticationManager;
@PostMapping("/signup")
public ResponseEntity<?> signup(@RequestBody SignupRequest request) {
if (!request.getPassword().equals(request.getConfirmPassword())) {
return ResponseEntity.badRequest().body(new ApiResponse<>("Passwords do not match", null));
}
if (userRepository.findByEmail(request.getEmail()).isPresent()) {
return ResponseEntity.badRequest().body(new ApiResponse<>("Email already in use", null));
}
User user = new User();
user.setName(request.getName());
user.setEmail(request.getEmail());
user.setPassword(passwordEncoder.encode(request.getPassword()));
user.setCreatedAt(java.time.LocalDateTime.now());
userRepository.save(user);
String token = jwtUtil.generateToken(user.getEmail());
return ResponseEntity.ok(new ApiResponse<>("Signup successful", new AuthResponse(user, token)));
}
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())
);
} catch (BadCredentialsException ex) {
return ResponseEntity.badRequest().body(new ApiResponse<>("Invalid email or password", null));
}
User user = userRepository.findByEmail(request.getEmail()).get();
String token = jwtUtil.generateToken(user.getEmail());
return ResponseEntity.ok(new ApiResponse<>("Login successful", new AuthResponse(user, token)));
}
}
AuthResponse.java (in payload)
package com.bankapp.payload;
import com.bankapp.model.User;
public class AuthResponse {
private User user;
private String token;
public AuthResponse(User user, String token) {
this.user = user;
this.token = token;
}
public User getUser() {
return user;
}
public String getToken() {
return token;
}
}
✅ Step 4: JwtUtil for Token Handling
JwtUtil.java (in security)
package com.bankapp.security;
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtUtil {
private final String jwtSecret = "supersecretkey123";
private final long jwtExpirationMs = 86400000;
public String generateToken(String email) {
return Jwts.builder()
.setSubject(email)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getEmailFromToken(String token) {
return Jwts.parser().setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (JwtException e) {
return false;
}
}
}
✅ Step 5: Jwt Filter + Security Config
package com.bankapp.security;
import com.bankapp.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.bankapp.model.User;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserRepository userRepository;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
String email = jwtUtil.getEmailFromToken(token);
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
User user = userRepository.findByEmail(email).orElse(null);
if (user != null && jwtUtil.validateToken(token)) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
user, null, null
);
auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
}
filterChain.doFilter(request, response);
}
}
package com.bankapp.config;
import com.bankapp.security.JwtAuthFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.security.authentication.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.*;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
@Autowired
private JwtAuthFilter jwtAuthFilter;
@Bean
public AuthenticationManager authManager(HttpSecurity http, PasswordEncoder encoder, UserDetailsService userDetailsService)
throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(userDetailsService)
.passwordEncoder(encoder)
.and()
.build();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
Let’s update both the AuthenticationManager and SecurityFilterChain beans to the modern Spring Security 6-compliant versions.
✅ Updated Version (Spring Security 6+ compatible)
📌 1. AuthenticationManager Bean
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
📌 2. SecurityFilterChain Bean (Spring Security 6+ style)
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
✅ 1. Permit /h2-console/** in your SecurityFilterChain
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // Disable CSRF for H2 Console
.headers(headers -> headers.frameOptions().disable()) // Allow frames (needed for H2 console)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/h2-console/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
✅ Updated SecurityFilterChain for Spring Security 6 (H2 console access included):
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // CSRF disabled for H2 Console
.headers(headers -> headers
.frameOptions(frame -> frame.disable()) // Modern way to disable X-Frame-Options
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**", "/h2-console/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
✅ Fix: Ensure @Configuration and @EnableWebSecurity Are Present
Please check your SecurityConfig class and make sure both of these annotations are present:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// your security config beans
}
Top comments (0)