Belajar Spring Boot - Security Dasar & Auth
Episode 12 of 24

Belajar Spring Boot - Security Dasar & Auth

Episode ini membuka Spring Security: filter chain, konfigurasi authentication manager dan user details, form login dan basic auth, serta perlindungan CSRF, CORS, dan security headers untuk aplikasi web dan API yang aman.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Keamanan bukan fitur tambahan — ia lapisan yang melindungi seluruh aplikasi. Episode 12 memperkenalkan Spring Security, standar de facto untuk autentikasi dan otorisasi di ekosistem Spring.

Kalian akan memahami filter chain yang menjadi tulang punggung keamanan, mengonfigurasi user dan authentication manager, memakai form login dan basic auth, serta mengaktifkan perlindungan CSRF, CORS, dan security headers. Episode 13 akan memperluas ini ke JWT dan OAuth 2.0.

Pengenalan Spring Security dan Filter Chain

Menambahkan Dependency

Tambahkan starter security ke project:

Dependency Spring Security
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Seketika seluruh endpoint terkunci — Spring Security mengaktifkan default yang menolak semua request tanpa autentikasi. Ini adalah perilaku yang aman secara default.

Filter Chain

Filter chain adalah rangkaian filter yang memproses setiap request sebelum mencapai controller. Setiap filter memiliki tanggung jawab: membaca credential, mengautentikasi, menerapkan otorisasi, dan menulis header keamanan.

Alur filter chain Spring Security
Request -> SecurityContextHolderFilter
        -> CsrfFilter
        -> UsernamePasswordAuthenticationFilter
        -> AuthorizationFilter
        -> Controller

Memahami urutan ini membantu membaca stack trace keamanan dan tahu filter mana yang menolak request kalian. Spring Boot 3 memakai SecurityFilterChain berbasis komponen yang dikonfigurasi dengan fluent API.

Mengonfigurasi Authentication Manager

UserDetailsService dan PasswordEncoder

Autentikasi memerlukan dua komponen: UserDetailsService untuk memuat user, dan PasswordEncoder untuk mencocokkan password. Mulai dengan user dari memory:

User in-memory dan encoder
@Bean
public UserDetailsService userDetailsService() {
    UserDetails admin = User.withUsername("admin")
            .password(passwordEncoder().encode("admin123"))
            .roles("ADMIN")
            .build();
    return new InMemoryUserDetailsManager(admin);
}
 
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

Jangan pernah menyimpan password plaintext. BCryptPasswordEncoder menghasilkan hash dengan salt otomatis — standard yang direkomendasikan. Untuk aplikasi nyata, implementasi UserDetailsService memuat user dari database.

Menghubungkan ke Database

Bentuk yang umum di produksi: user disimpan di database dan dimuat lewat repository:

UserDetailsService dari database
@Service
public class CustomUserDetailsService
        implements UserDetailsService {
 
    private final UserRepository repository;
 
    public CustomUserDetailsService(UserRepository repository) {
        this.repository = repository;
    }
 
    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        return repository.findByUsername(username)
                .map(user -> User.withUsername(user.getUsername())
                        .password(user.getPassword())
                        .roles(user.getRole())
                        .build())
                .orElseThrow(() -> new UsernameNotFoundException(
                        "User tidak ditemukan"));
    }
}

Dengan pola ini, autentikasi berasal dari data sungguhan di database. Hash password tetap memakai BCryptPasswordEncoder.

Konfigurasi SecurityFilterChain

Form Login dan Basic Auth

Atur kebijakan keamanan dengan SecurityFilterChain. Contoh memakai form login untuk aplikasi web dan mengizinkan halaman publik:

Security filter chain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
        throws Exception {
    return http
            .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/", "/home", "/register")
                    .permitAll()
                    .requestMatchers("/api/admin/**")
                    .hasRole("ADMIN")
                    .anyRequest().authenticated())
            .formLogin(Customizer.withDefaults())
            .httpBasic(Customizer.withDefaults())
            .build();
}

Aturan dibaca dari atas ke bawah: halaman publik diizinkan tanpa login, area admin hanya untuk role ADMIN, dan sisanya butuh autentikasi. Urutan requestMatchers sangat menentukan hasil akhir.

Perlindungan CSRF, CORS, dan Security Headers

CSRF untuk Browser vs Stateless API

CSRF melindungi dari serangan yang memaksa user terautentikasi mengirim request berbahaya. Spring mengaktifkannya secara default dengan token CSRF. Untuk REST API stateless yang memakai token (bukan cookie), CSRF tidak terlalu relevan dan sering dimatikan:

Nonaktifkan CSRF untuk API stateless
return http
        .csrf(csrf -> csrf.disable())
        .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated())
        .build();

Untuk aplikasi web berbasis cookie dan form login, biarkan CSRF aktif. Keputusan ini bergantung pada mekanisme autentikasi yang dipakai — token bearer tidak memerlukan CSRF, session cookie memerlukannya.

CORS dan Security Headers

CORS mengontrol origin mana yang boleh mengakses API dari browser:

Konfigurasi CORS
return http
        .cors(cors -> cors.configurationSource(request -> {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedOrigins(List.of("https://app.example.com"));
            config.setAllowedMethods(List.of("GET", "POST", "PUT"));
            config.setAllowedHeaders(List.of("Authorization"));
            return config;
        }))
        .build();

Jangan buka semua origin kecuali benar-benar diperlukan — batasi ke domain yang kalian kuasai. Selain itu, Spring menambahkan security headers otomatis: X-Content-Type-Options, Strict-Transport-Security, dan frame options, yang melindungi dari berbagai serangan browser.

Menguji Keamanan

Uji konfigurasi dengan curl. Tanpa credential, request akan ditolak dengan status 401:

Tes autentikasi dasar
curl -I http://localhost:8080/api/items
curl -u admin:admin123 http://localhost:8080/api/admin

Perintah curl -u admin:admin123 http://localhost:8080/api/admin mengirim basic auth — header Authorization yang berisi username dan password. Request pertama tanpa credential akan menerima 401 Unauthorized, dan yang kedua hanya sukses untuk user dengan role ADMIN.

Penutup

Episode 12 membekali kalian dengan keamanan dasar Spring Security: memahami filter chain, mengonfigurasi authentication manager dengan UserDetailsService dan PasswordEncoder, menetapkan aturan akses di SecurityFilterChain, serta mengaktifkan perlindungan CSRF, CORS, dan security headers.

Inti yang harus dibawa pulang:

  • spring-boot-starter-security mengunci seluruh endpoint secara default.
  • UserDetailsService memuat user; BCryptPasswordEncoder menghash password.
  • SecurityFilterChain menetapkan aturan otorisasi dengan requestMatchers.
  • CSRF wajib untuk aplikasi session-based; bisa dimatikan untuk API stateless.
  • Batasi origin CORS ke domain yang kalian kuasai.
  • Security headers ditambahkan otomatis oleh Spring Security.

Di episode 13 selanjutnya kita akan membahas OAuth 2.0 dan JWT — peran authorization server vs resource server, implementasi token-based auth dengan JWT, integrasi identity provider eksternal seperti Keycloak, serta best practice refresh token dan scopes.

Belajar Spring Boot - Security Dasar & Auth | Belajar Spring Boot