Wszystkie artykuły
RestController Spring Boot na embedded Tomcat weryfikuje nagłówki podpisu webhook z surowego byte[] payload przez lokalny tunel.
Spring BootJavawebhook debugginglocal testing

Webhooki Spring Boot: surowe body, wyjątek CSRF i nagłówki podpisu

Spring Boot ułatwia endpointy webhook przez @RestController, ale Spring Security CSRF i konwertery JSON mogą blokować lub zmieniać payload przed handlerem. Test lokalny powinien potwierdzić dostęp do byte[], wyjątki CSRF na ścieżkach webhook i weryfikację podpisu na nietkniętych bajtach.

Utwórz endpoint webhook @RestController

Trzymaj kontrolery webhook lekkie. Przyjmuj surowe bajty, weryfikuj podpis, potem deserializuj:

@RestController
@RequestMapping("/webhooks")
public class StripeWebhookController {

    @PostMapping("/stripe")
    public ResponseEntity handle(
            @RequestBody byte[] payload,
            @RequestHeader("Stripe-Signature") String signature) {

        if (!verifier.isValid(payload, signature)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
        JsonNode event = objectMapper.readTree(payload);
        handler.process(event);
        return ResponseEntity.ok().build();
    }
}

@RequestBody byte[] zachowuje dokładny payload od Tomcat — idealne gdy provider podpisuje surowy JSON.

Czytaj surowe body przez HttpServletRequest

Alternatywnie czytaj bezpośnio z żądania servlet:

byte[] body = request.getInputStream().readAllBytes();
String sig = request.getHeader("Stripe-Signature");

Nie binduj najpierw do POJO ani Map — reserializacja Jackson psuje HMAC. Zobacz przewodnik weryfikacji podpisu.

Wyłącz CSRF tylko dla ścieżek webhook

Spring Security domyślnie włącza CSRF. POST webhook kończy się 403 bez wyjątku server-to-server:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.ignoringRequestMatchers("/webhooks/**"));
        return http.build();
    }
}

Ogranicz ignore do /webhooks/** — nie wyłączaj CSRF globalnie.

Weryfikuj nagłówki podpisu przed logiką biznesową

Czytaj nagłówki providera, oblicz digest z tablicy bajtów i porównuj w stałym czasie. 401 przy błędzie, szybkie 200 przy sukcesie.

Lokalny workflow tunelu

  1. Uruchom: ./mvnw spring-boot:run na porcie 8080.
  2. Wystaw Tomcat: npx portpreview 8080.
  3. Wklej URL tunelu + ścieżkę w dashboardzie.
  4. Wyślij zdarzenie testowe i obserwuj logi.
  5. Powtórz event ID dla idempotencji — zobacz wzorce retry.

Typowe pułapki

Kolejność filtrów i konsumpcja body

Filtry czytające stream przed kontrolerem zostawiają pusty strumień. Użyj ContentCachingRequestWrapper.

Globalne wiązanie @RequestBody

Globalny @ControllerAdvice z wczesnym parsowaniem JSON może zmienić bajty. Izoluj webhook z byte[].

Wolne handlery wywołują retry

Szybko potwierdzaj, przetwarzaj async, deduplikuj po event ID.

Więcej

Podstawy znajdziesz w podstawach tunelowania localhost oraz praktycznym lokalnym debugowaniu webhooków. Mechanika podpisu — w przewodniku weryfikacji podpisu. Obsługa bez duplikatów — w wzorach retry i idempotencji. zacznij PortPreview za darmo.

Najczęściej zadawane pytania

Dlaczego webhooki Spring Boot zwracają 403?
CSRF Spring Security blokuje POST bez tokenu sesji. Dodaj csrf.ignoringRequestMatchers dla ścieżki webhook i weryfikuj podpis.
byte[] czy POJO dla webhooków?
Użyj byte[] do weryfikacji podpisu. Binding POJO reserializuje JSON i psuje HMAC.
Jak testować webhooki Spring Boot lokalnie?
Uruchom spring-boot:run na 8080, wystaw przez npx portpreview, wklej URL tunelu i wywołaj zdarzenia testowe.