Spring Security 6 en JWT-authenticatie · Les

Een aangepast JWT-filter implementeren

Bouw een aangepaste `OncePerRequestFilter` om verzoeken te onderscheppen, JWT's eruit te halen en gebruikers te authenticeren.

Les 2 van 411 stappen

Een aangepast JWT-filter implementeren is een gratis Spring Security 6 en JWT-authenticatie-les op CoddyKit. Dit is les 2 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Spring Security 6 en JWT-authenticatie. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Spring Security 6 en JWT-authenticatie bevat in totaal 4 lessen.

Waarom een aangepast JWT-filter?

Wanneer je JSON Web Tokens (JWT's) gebruikt voor authenticatie, weet Spring Security niet automatisch hoe het deze moet verwerken. Daar komt een aangepast filter van pas!

Een aangepast JWT-filter onderschept binnenkomende verzoeken om:

  • De JWT uit te lezen.
  • De authenticiteit en vervaldatum ervan te valideren.
  • Spring Security te informeren over de geauthenticeerde gebruiker.

De basis van OncePerRequestFilter

Voor ons aangepaste JWT-filter breiden we Spring's OncePerRequestFilter uit. Deze basisklasse garandeert dat de logica van je filter precies één keer per HTTP-verzoek wordt uitgevoerd, zodat overbodige verwerking wordt voorkomen.

  • De implementatie van het filter wordt eenvoudiger.
  • De efficiëntie voor elk verzoek wordt gewaarborgd.
  • Het is ideaal voor authenticatielogica.

Basisstructuur van een filter

Elk aangepast filter dat OncePerRequestFilter uitbreidt, moet de doFilterInternal-methode overschrijven. Hier komt onze JWT-verwerkingslogica te staan.

Het filter krijgt toegang tot HttpServletRequest, HttpServletResponse en FilterChain om het verzoek door te geven.

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
        HttpServletRequest request,
        HttpServletResponse response,
        FilterChain filterChain
    ) throws ServletException, IOException {
        // Our JWT logic will go here
        filterChain.doFilter(request, response);
    }
}

De JWT uitlezen

De eerste stap in ons filter is de JWT uit het binnenkomende verzoek halen. JWT's worden meestal verzonden in de Authorization-header, voorafgegaan door Bearer .

We moeten controleren of deze header aanwezig is en het gedeelte 'Bearer ' verwijderen om het onbewerkte token te verkrijgen.

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
        HttpServletRequest request,
        HttpServletResponse response,
        FilterChain filterChain
    ) throws ServletException, IOException {
        final String authHeader = request.getHeader("Authorization");
        String jwt = null;

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            jwt = authHeader.substring(7); // Remove "Bearer " prefix
            System.out.println("Extracted JWT: " + jwt.substring(0, 5) + "...");
        } else {
            System.out.println("No JWT found or invalid header.");
        }

        filterChain.doFilter(request, response);
    }
}

Valideren en parseren (concept)

Na het uitlezen moet de JWT worden gevalideerd. Dit omvat:

  • Handtekeningverificatie: Controleren of er niet met het token is geknoeid.
  • Controle van de vervaldatum: Bevestigen dat het token nog geldig is.
  • Claims uitlezen: Informatie zoals de gebruikersnaam (subject) uit de payload van het token halen.

Deze validatie wordt meestal afgehandeld door een speciale JwtService of vergelijkbaar hulpprogramma, dat ons filter zou gebruiken.

Gebruikersgegevens laden (concept)

Nadat de JWT is gevalideerd en de gebruikersnaam (of gebruikers-ID) is uitgelezen, moet het filter de specifieke gegevens van de gebruiker laden. Dit gebeurt meestal met Spring Security's UserDetailsService.

De UserDetailsService haalt het object UserDetails op, dat informatie bevat zoals rollen en autoriteiten die nodig zijn voor autorisatie.

De authenticatiecontext instellen

De laatste cruciale stap is Spring Security informeren dat de gebruiker voor het huidige verzoek is geauthenticeerd. Dit doe je door een Authentication-object (bijvoorbeeld UsernamePasswordAuthenticationToken) aan te maken en dit in de SecurityContextHolder te plaatsen.

Nadat dit is ingesteld, herkent Spring Security de gebruiker gedurende de rest van het verzoek als geauthenticeerd.

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // Simulate a UserDetails object loaded from DB
        UserDetails userDetails = new User(
            "exampleUser", "[PASSWORD_HASH]", new ArrayList<>()
        );

        // Create an Authentication token
        UsernamePasswordAuthenticationToken authToken =
            new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities()
            );

        // Set the Authentication in the SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(authToken);

        System.out.println("Authentication set for: " +
            SecurityContextHolder.getContext().getAuthentication().getName());

        // Clear context after request (or for next test)
        SecurityContextHolder.clearContext();
    }
}

Voorbeeld van uitvoerbare filterlogica

Laten we een vereenvoudigd, uitvoerbaar voorbeeld bekijken dat de kernlogica van ons aangepaste JWT-filter nabootst. Het simuleert het uitlezen van een token en het instellen van authenticatie op basis van de aanwezigheid ervan.

Dit voorbeeld gebruikt nagebootste componenten om de stroom te laten zien zonder een volledige Spring Boot-configuratie.

import java.util.HashMap;
import java.util.Map;

// Simulate Spring Security components needed for the filter logic
class MockSecurityContextHolder {
    private static String authenticatedUser = null;

    public static String getAuthentication() {
        return authenticatedUser;
    }

    public static void setAuthentication(String user) {
        authenticatedUser = user;
    }

    public static void clearContext() {
        authenticatedUser = null;
    }
}

public class Main {

    // This method simulates the core logic of doFilterInternal
    public static void simulateJwtFilter(Map<String, String> requestHeaders) {
        System.out.println("--- Simulating JWT Filter Logic ---");

        final String authHeader = requestHeaders.get("Authorization");
        String jwt = null;
        String username = null;

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            jwt = authHeader.substring(7);
            // In a real app, this extracts username from JWT payload
            username = "coddyuser"; // Simplified: assume "coddyuser" from a valid JWT
            System.out.println("Filter: JWT found: " + jwt.substring(0, 5) + "...");
        } else {
            System.out.println("Filter: No JWT found or invalid header format.");
        }

        // Check if user is already authenticated
        if (username != null && MockSecurityContextHolder.getAuthentication() == null) {
            // Simulate JWT validation (signature, expiration, etc.)
            boolean tokenValid = true; // Assume valid for this simple demo

            if (tokenValid) {
                // In a real filter, we'd load UserDetails and create an Authentication object
                MockSecurityContextHolder.setAuthentication(username);
                System.out.println("Filter: User '" + username + "' authenticated and context set.");
            } else {
                System.out.println("Filter: JWT validation failed.");
            }
        } else if (username != null && MockSecurityContextHolder.getAuthentication() != null) {
            System.out.println("Filter: User '" + username + "' already authenticated for this request.");
        }

        // In a real filter, this would call filterChain.doFilter(...)
        System.out.println("Filter: Request passed to next filter/handler.");
        System.out.println("--- Filter Logic End ---");
    }

    public static void main(String[] args) {
        // Scenario 1: Request with a valid JWT
        Map<String, String> headers1 = new HashMap<>();
        headers1.put("Authorization", "Bearer abc.def.ghi");
        simulateJwtFilter(headers1);
        System.out.println("Main: SecurityContext has authentication: " +
            (MockSecurityContextHolder.getAuthentication() != null ? MockSecurityContextHolder.getAuthentication() : "None"));
        MockSecurityContextHolder.clearContext(); // Clean up

        System.out.println("\n");

        // Scenario 2: Request without a JWT
        Map<String, String> headers2 = new HashMap<>();
        simulateJwtFilter(headers2);
        System.out.println("Main: SecurityContext has authentication: " +
            (MockSecurityContextHolder.getAuthentication() != null ? MockSecurityContextHolder.getAuthentication() : "None"));
        MockSecurityContextHolder.clearContext(); // Clean up
    }
}

Integratie met Spring Security

Nadat we ons JwtAuthenticationFilter hebben gemaakt, moeten we dit registreren bij de filterketen van Spring Security. Dit gebeurt meestal in de beveiligingsconfiguratieklasse (bijvoorbeeld SecurityConfig) met behulp van HttpSecurity.

We gebruiken .addFilterBefore() om ervoor te zorgen dat ons JWT-filter wordt uitgevoerd vóór de standaardauthenticatiefilters van Spring Security, zoals UsernamePasswordAuthenticationFilter.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

// Assuming JwtAuthenticationFilter is defined elsewhere
class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response, jakarta.servlet.FilterChain filterChain) throws jakarta.servlet.ServletException, java.io.IOException {
        // Simplified for config demo
        filterChain.doFilter(request, response);
    }
}

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthFilter;

    // Inject our custom JWT filter
    public SecurityConfig(JwtAuthenticationFilter jwtAuthFilter) {
        this.jwtAuthFilter = jwtAuthFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // Disable CSRF for stateless APIs
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll() // Public endpoints
                .anyRequest().authenticated() // Secure all other requests
            )
            // Add our custom JWT filter BEFORE the default UsernamePasswordAuthenticationFilter
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

Uitdaging: filterketen

Denk na over het JwtAuthenticationFilter dat we hebben besproken. Wat zijn de belangrijkste verantwoordelijkheden ervan in de filterketen van Spring Security bij het afhandelen van JWT-gebaseerde authenticatie?

Lesoverzicht: aangepast JWT-filter

In deze les hebben we onderzocht hoe je een aangepast OncePerRequestFilter bouwt voor JWT-authenticatie in Spring Security.

  • We hebben geleerd JWT's uit de Authorization-header te halen.
  • We hebben de conceptuele stappen van het valideren van het token en het laden van gebruikersgegevens begrepen.
  • We hebben gezien hoe je de gebruiker authenticeert door de SecurityContextHolder in te stellen.
  • Tot slot hebben we behandeld hoe je dit filter integreert in de filterketen van Spring Security met HttpSecurity.addFilterBefore().

Dit aangepaste filter is essentieel om JWT's naadloos te integreren in je beveiligde Spring Boot-toepassingen.

Gratis beginnen

Leer Java met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
12
Lessen
48

Veelgestelde vragen

Is de les “Een aangepast JWT-filter implementeren” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad Spring Security 6 en JWT-authenticatie, waaronder “Een aangepast JWT-filter implementeren”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Spring Security 6 en JWT-authenticatie bevat in totaal 4 lessen.

Wat leer ik in “Een aangepast JWT-filter implementeren”?

Bouw een aangepaste `OncePerRequestFilter` om verzoeken te onderscheppen, JWT's eruit te halen en gebruikers te authenticeren. Je oefent met Spring Security 6 en JWT-authenticatie door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Spring Security 6 en JWT-authenticatie te beginnen?

Ervaring vooraf is niet nodig. Spring Security 6 en JWT-authenticatie op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Een aangepast JWT-filter implementeren”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Spring Security 6 en JWT-authenticatie?

Ja. Elke les over Spring Security 6 en JWT-authenticatie bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. De JWT-authenticatiestroom ontwerpen
  2. Een aangepast JWT-filter implementeren
  3. Integratie van AuthenticationManager en providers
  4. Authenticatiefouten en entry points afhandelen
← Terug naar Spring Security 6 en JWT-authenticatie