Spring Security 6 en JWT-authenticatie · Les

Beveiliging op methodeniveau met annotaties

Beveilig afzonderlijke methoden in uw servicelaag met Spring Security-annotaties zoals `@PreAuthorize` en `@PostAuthorize`.

Les 2 van 411 stappen

Beveiliging op methodeniveau met annotaties 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.

Introductie tot beveiliging op methoden

Welkom! In Spring Security beveiligen we web-eindpunten vaak met HttpSecurity. Maar wat als je fijnmazigere controle binnen je applicatielogica nodig hebt?

Met beveiliging op methoden kun je afzonderlijke methoden in je servicelaag beveiligen, zodat alleen geautoriseerde gebruikers ze kunnen aanroepen. Dit voegt nog een krachtige verdedigingslaag toe!

Beveiliging op methoden inschakelen

Als je beveiliging op methoden wilt gebruiken, moet je deze inschakelen in je Spring Security-configuratie. Dit doe je met de annotatie @EnableMethodSecurity.

Plaats deze op je hoofdklasse voor de beveiligingsconfiguratie, meestal een klasse die WebSecurityConfigurerAdapter uitbreidt (hoewel je in Spring Security 6 vaak gewoon een @Configuration-klasse met een FilterChainBean gebruikt).

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;

@Configuration
@EnableMethodSecurity // Enables @PreAuthorize, @PostAuthorize, etc.
public class SecurityConfig {
    // Your security filter chain bean goes here
}

@PreAuthorize: vóór uitvoering

De annotatie @PreAuthorize controleert de autorisatie voordat een methode wordt uitgevoerd. Als niet aan de voorwaarde wordt voldaan, wordt de methode niet uitgevoerd en wordt een AccessDeniedException gegenereerd.

De annotatie gebruikt de Spring Expression Language (SpEL) om krachtige autorisatieregels te definiëren. Veelgebruikte toepassingen zijn het controleren van rollen of specifieke bevoegdheden.

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

@Service
public class AdminService {

    @PreAuthorize("hasRole('ADMIN')")
    public String deleteSensitiveData() {
        return "Sensitive data deleted!";
    }

    @PreAuthorize("hasAuthority('product:write')")
    public String createProduct(String productName) {
        return "Product '" + productName + "' created.";
    }
}

Het voorbeeld met @PreAuthorize uitvoeren

Laten we @PreAuthorize in actie bekijken. Dit uitvoerbare voorbeeld bootst na hoe Spring Security de controle hasRole('ADMIN') zou verwerken door handmatig de rol van een gebruiker in de beveiligingscontext in te stellen.

Voer het voorbeeld uit om te zien hoe toegang wordt verleend of geweigerd op basis van de toegewezen rol.

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import java.util.Collections;
import java.util.List;

public class Main {

    // This method simulates a service method protected by @PreAuthorize("hasRole('ADMIN')")
    public static String getAdminMessage() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        // In a real Spring app, AOP would handle this check before method entry.
        // We simulate it here for demonstration.
        if (auth != null && auth.getAuthorities().stream()
                .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
            return "Welcome, Admin! Here's your secret message.";
        } else {
            return "Access Denied: ADMIN role required.";
        }
    }

    public static void main(String[] args) {
        // Scenario 1: User with ADMIN role
        List<GrantedAuthority> adminAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"));
        Authentication adminAuth = new UsernamePasswordAuthenticationToken("adminUser", "pass", adminAuthorities);
        SecurityContextHolder.getContext().setAuthentication(adminAuth);
        System.out.println("Admin user attempt: " + getAdminMessage());

        // Scenario 2: User with USER role
        List<GrantedAuthority> userAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
        Authentication userAuth = new UsernamePasswordAuthenticationToken("regularUser", "pass", userAuthorities);
        SecurityContextHolder.getContext().setAuthentication(userAuth);
        System.out.println("\nRegular user attempt: " + getAdminMessage());

        SecurityContextHolder.clearContext(); // Clean up
    }
}

SpEL voor dynamische controles

Met @PreAuthorize kun je meer doen dan alleen rollen controleren! Je kunt SpEL gebruiken om methodeargumenten, de geauthenticeerde principal of zelfs aangepaste beans te benaderen.

Zo verwijst #userId naar een methodeparameter met de naam userId. authentication.principal.username haalt de gebruikersnaam van de huidige gebruiker op.

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // Only allow users to view their own profile
    @PreAuthorize("#userId == authentication.principal.username")
    public String viewUserProfile(String userId) {
        return "Viewing profile for: " + userId;
    }

    // Allow ADMIN or the owner of the resource
    @PreAuthorize("hasRole('ADMIN') or #resourceOwner == authentication.principal.username")
    public String editResource(String resourceId, String resourceOwner) {
        return "Editing resource '" + resourceId + "' by '" + resourceOwner + "'.";
    }
}

@PostAuthorize: na uitvoering

Soms moet je een autorisatiebeslissing nemen nadat de methode is uitgevoerd en je toegang hebt tot de geretourneerde waarde. Daarvoor gebruik je @PostAuthorize.

Dit is nuttig om te controleren of de geauthenticeerde gebruiker de gegevens die de methode zojuist heeft opgehaald of verwerkt, ook mag *bekijken*. Je kunt de geretourneerde waarde in SpEL benaderen via returnObject.

import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;

// A simple data class for demonstration
class UserProfile {
    String username;
    String email;
    public UserProfile(String username, String email) {
        this.username = username;
        this.email = email;
    }
    public String getUsername() { return username; }
    public String getEmail() { return email; }
}

@Service
public class ProfileService {

    // Only allow access to profile if current user is the owner or an ADMIN
    @PostAuthorize("returnObject.username == authentication.principal.username or hasRole('ADMIN')")
    public UserProfile getUserProfile(String requestedUsername) {
        // In a real app, this would fetch from a database
        if ("john.doe".equals(requestedUsername)) {
            return new UserProfile("john.doe", "john@example.com");
        }
        return new UserProfile("guest", "guest@example.com");
    }
}

Het voorbeeld met @PostAuthorize uitvoeren

Dit voorbeeld demonstreert @PostAuthorize. We simuleren dat er een UserProfile wordt geretourneerd en controleren vervolgens of de huidige geauthenticeerde gebruiker dit profiel mag bekijken.

Let erop dat de controle plaatsvindt *nadat* de methode getUserProfile het resultaat heeft opgeleverd.

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import java.util.Collections;
import java.util.List;

// Simple data class for demonstration
class UserProfile {
    String username;
    String email;
    public UserProfile(String username, String email) {
        this.username = username;
        this.email = email;
    }
    public String getUsername() { return username; }
    public String getEmail() { return email; }
    @Override
    public String toString() { return "Profile: " + username + " (" + email + ")"; }
}

public class Main {

    // Simulates a service method with @PostAuthorize("returnObject.username == authentication.principal.username")
    public static UserProfile getSecuredUserProfile(String requestedUsername) {
        UserProfile profile = new UserProfile(requestedUsername, requestedUsername + "@example.com");
        
        // Simulate @PostAuthorize check
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.isAuthenticated() && 
            profile.getUsername().equals(auth.getName())) {
            return profile; // Allowed to view own profile
        } else if (auth != null && auth.isAuthenticated() && 
                   auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"))) {
            return profile; // Admin can view any profile
        } else {
            // In a real app, this would be an AccessDeniedException
            System.out.println("Access Denied to view profile for " + requestedUsername);
            return null; // Or throw an exception
        }
    }

    public static void main(String[] args) {
        // Scenario 1: User viewing their own profile
        List<GrantedAuthority> userAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
        Authentication userAuth = new UsernamePasswordAuthenticationToken("alice", "pass", userAuthorities);
        SecurityContextHolder.getContext().setAuthentication(userAuth);
        System.out.println("Alice viewing her own profile: " + getSecuredUserProfile("alice"));

        // Scenario 2: Alice trying to view Bob's profile
        System.out.println("\nAlice viewing Bob's profile: " + getSecuredUserProfile("bob"));

        // Scenario 3: Admin viewing Bob's profile
        List<GrantedAuthority> adminAuthorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_ADMIN"));
        Authentication adminAuth = new UsernamePasswordAuthenticationToken("admin", "pass", adminAuthorities);
        SecurityContextHolder.getContext().setAuthentication(adminAuth);
        System.out.println("\nAdmin viewing Bob's profile: " + getSecuredUserProfile("bob"));

        SecurityContextHolder.clearContext();
    }
}

Collecties filteren: @PreFilter en @PostFilter

Voor methoden die collecties accepteren of retourneren, biedt Spring Security @PreFilter en @PostFilter.

  • @PreFilter: Filtert een collectieargument *voordat* de methode wordt uitgevoerd.
  • @PostFilter: Filtert de geretourneerde collectie *nadat* de methode is uitgevoerd.

Deze annotaties zijn krachtig voor situaties waarin je een gebruiker bijvoorbeeld alleen de items in een lijst wilt tonen die van die gebruiker zijn, of updates alleen voor specifieke elementen in een verzameling wilt toestaan.

import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.access.prepost.PostFilter;
import java.util.List;

class Item { String owner; String name; }

public class ItemService {

    // Only allow items owned by the current user to be processed
    @PreFilter("filterObject.owner == authentication.principal.username")
    public void processItems(List<Item> items) {
        // ... process only allowed items ...
    }

    // Only return items owned by the current user
    @PostFilter("filterObject.owner == authentication.principal.username")
    public List<Item> getAllItemsForUser() {
        // ... fetch all items from DB ...
        return List.of(new Item(), new Item()); // Returns filtered list
    }
}

Aanbevolen werkwijzen voor beveiliging op methoden

Zo gebruik je beveiliging op methoden effectief:

  • Pas deze toe op de servicelaag: Houd bedrijfslogica gescheiden van controllers. Beveilig je servicemethoden.
  • Combineer met HttpSecurity: Gebruik op URL's gebaseerde beveiliging voor brede toegangscontrole en beveiliging op methoden voor fijnmazige machtigingen. Ze vullen elkaar aan.
  • Houd SpEL beknopt: Complexe SpEL kan moeilijk te lezen en te debuggen zijn. Overweeg aangepaste machtigingsevaluators voor zeer ingewikkelde logica.
  • Test grondig: Test je beveiligingsregels altijd om te controleren of ze zich gedragen zoals verwacht.

Korte controle: methode-annotaties

Je bouwt een applicatie en moet ervoor zorgen dat de methode public void deleteUser(String userId) alleen kan worden aangeroepen door een gebruiker met de rol ADMIN, EN alleen als userId overeenkomt met de ID van de momenteel geauthenticeerde gebruiker.

Welke @PreAuthorize-expressie legt dit correct af?

Samenvatting en volgende stappen

Goed gedaan! Je hebt geleerd hoe beveiliging op methoden werkt in Spring Security.

  • @EnableMethodSecurity activeert deze functie.
  • @PreAuthorize controleert machtigingen *vóór* de uitvoering van een methode.
  • @PostAuthorize controleert machtigingen *na* de uitvoering van een methode en inspecteert de geretourneerde waarde.
  • @PreFilter en @PostFilter helpen bij het filteren van collectieargumenten of geretourneerde waarden.

Met dit krachtige hulpmiddel bepaal je zeer precies wie toegang heeft tot de interne bewerkingen van je applicatie. Blijf oefenen en ontdek de mogelijkheden van SpEL!

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 “Beveiliging op methodeniveau met annotaties” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad Spring Security 6 en JWT-authenticatie, waaronder “Beveiliging op methodeniveau met annotaties”, 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 “Beveiliging op methodeniveau met annotaties”?

Beveilig afzonderlijke methoden in uw servicelaag met Spring Security-annotaties zoals `@PreAuthorize` en `@PostAuthorize`. 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 “Beveiliging op methodeniveau met annotaties”?

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. Op rollen gebaseerd toegangsbeheer (RBAC)
  2. Beveiliging op methodeniveau met annotaties
  3. HttpSecurity-configuratie uitgediept
  4. Endpoints beveiligen met aangepaste toegangsregels
← Terug naar Spring Security 6 en JWT-authenticatie