JWT Authentication Filter
Building on our authentication implementation from previous lessons, we'll now create a filter to validate JWT tokens on protected endpoints.
This filter enables stateless authentication by validating tokens and establishing user context for each request.
Authentication Service Enhancement
The AuthenticationService interface needs to validate incoming tokens:
public interface AuthenticationService {
// ... existing methods ...
UserDetails validateToken(String token);
}Token Validation Implementation
The AuthenticationServiceImpl must decode and validate JWT tokens:
private String extractUsername(String token) {
return extractAllClaims(token).getSubject();
}
private Claims extractAllClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody();
}
@Override
public UserDetails validateToken(String token) {
String username = extractUsername(token);
return userDetailsService.loadUserByUsername(username);
}JWT Filter Implementation
The JwtAuthenticationFilter processes each request to validate authentication:
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final AuthenticationService authenticationService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
try {
String token = extractToken(request);
if (token != null) {
UserDetails userDetails = authenticationService.validateToken(token);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Add userId to request attributes for controller access
if (userDetails instanceof BlogUserDetails) {
request.setAttribute("userId", ((BlogUserDetails) userDetails).getId());
}
}
} catch (Exception e) {
// Don't throw exceptions here - just don't authenticate the request
log.warn("Received invalid auth token");
}
filterChain.doFilter(request, response);
}
private String extractToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}Enabling the Filter
Update the SecurityConfig to use our new filter:
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter(
AuthenticationService authenticationService) {
return new JwtAuthenticationFilter(authenticationService);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http,
JwtAuthenticationFilter jwtAuthenticationFilter)
throws Exception {
http
// ... existing configuration ...
.addFilterBefore(jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);
return http.build();
}Summary
- Created JWT authentication filter to process token-based authentication
- Extended authentication service with token validation capabilities
- Implemented secure token extraction and validation logic
- Added user context to requests for controller access
- Integrated filter into Spring Security chain for automatic processing