0Pricing
Spring Security 6 & JWT Authentication · 강의

데이터베이스 사용자 관리 통합

영속 데이터 소스에 저장된 사용자를 관리하고 인증하도록 Spring Security를 데이터베이스와 통합합니다.

데이터베이스 사용자 관리 통합은(는) CoddyKit의 무료 Spring Security 6 & JWT Authentication 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Spring Security 6 & JWT Authentication 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Spring Security 6 & JWT Authentication 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

DB for User Management

Welcome! So far, we've used in-memory users. But real applications need to store user data persistently. That's where databases come in!

In this lesson, you'll learn how to integrate Spring Security with a database to manage and authenticate your application's users.

Why Use a Database?

Storing users in a database offers several key benefits:

  • Persistence: User data isn't lost when your app restarts.
  • Scalability: Easily manage a large number of users.
  • Flexibility: Store additional user attributes (e.g., email, roles, profile info).
  • Centralized Management: A single source of truth for all user data.

Basic User Table

First, we need a database table to hold our users. A simple users table and an authorities table (for roles) might look like this:

These tables typically contain at least a username, password, and an 'enabled' status for the user, and a username and authority (role) for permissions.

CREATE TABLE users (
  username VARCHAR(50) NOT NULL PRIMARY KEY,
  password VARCHAR(500) NOT NULL,
  enabled  BOOLEAN NOT NULL
);

CREATE TABLE authorities (
  username VARCHAR(50) NOT NULL,
  authority VARCHAR(50) NOT NULL,
  CONSTRAINT fk_authorities_users FOREIGN KEY (username) REFERENCES users (username)
);

Custom UserDetailsService

Recall that UserDetailsService is the core interface Spring Security uses to retrieve user details. For database integration, we'll create or use an implementation that fetches user data from our database.

This service builds a UserDetails object (containing username, password, and roles) from the retrieved data.

package org.springframework.security.core.userdetails;

public interface UserDetailsService {
  UserDetails loadUserByUsername(String username)
      throws UsernameNotFoundException;
}

Using JdbcUserDetailsManager

Spring Security provides JdbcUserDetailsManager, a convenient built-in implementation of UserDetailsService that uses JDBC (Java Database Connectivity) to interact with your database.

It expects specific table schemas (like the one shown earlier) to function correctly. You just need to provide it with a DataSource.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import javax.sql.DataSource;

@Configuration
public class UserManagementConfig {

  @Bean
  public UserDetailsService userDetailsService(DataSource dataSource) {
    JdbcUserDetailsManager userDetailsManager = new JdbcUserDetailsManager(dataSource);
    // Custom queries can be set if your schema differs:
    // userDetailsManager.setUsersByUsernameQuery("SELECT ...");
    // userDetailsManager.setAuthoritiesByUsernameQuery("SELECT ...");
    return userDetailsManager;
  }
}

Secure Password Storage

When storing passwords in a database, it's crucial to never store them in plain text. Always use a Password Encoder to hash them securely.

BCryptPasswordEncoder is a popular and robust choice, providing strong, one-way hashing for passwords.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class PasswordEncoderConfig {

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }
}

Wiring Authentication

To complete the integration, we need to tell Spring Security to use our database-backed UserDetailsService and the chosen PasswordEncoder.

This is typically done by configuring the SecurityFilterChain, where we explicitly set these components for authentication.

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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

  private final UserDetailsService userDetailsService;
  private final PasswordEncoder passwordEncoder;

  public WebSecurityConfig(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
    this.userDetailsService = userDetailsService;
    this.passwordEncoder = passwordEncoder;
  }

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(authorize -> authorize
        .anyRequest().authenticated()
      )
      .formLogin(form -> form.permitAll())
      .userDetailsService(userDetailsService)
      .passwordEncoder(passwordEncoder);
    return http.build();
  }
}

Complete DB Auth Example

Here's a full runnable Spring Boot application that uses an in-memory H2 database, JdbcUserDetailsManager, and BCryptPasswordEncoder. It also creates some initial users.

Run it, then try to access /hello. You'll be prompted to log in with 'user'/'password' or 'admin'/'adminpass'.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;

@SpringBootApplication
@RestController
public class DatabaseAuthApp {

  public static void main(String[] args) {
    SpringApplication.run(DatabaseAuthApp.class, args);
  }

  @GetMapping("/hello")
  public String hello() {
    return "Hello, secured world!";
  }

  @Configuration
  @EnableWebSecurity
  static class WebSecurityConfig {

    // 1. Configure DataSource for H2 in-memory database
    @Bean
    public DataSource dataSource() {
      return new EmbeddedDatabaseBuilder()
          .setType(EmbeddedDatabaseType.H2)
          .addScript("classpath:org/springframework/security/core/userdetails/jdbc/users.ddl")
          .build();
    }

    // 2. Configure JdbcUserDetailsManager to use the DataSource
    @Bean
    public UserDetailsService userDetailsService(DataSource dataSource, PasswordEncoder passwordEncoder) {
      JdbcUserDetailsManager userDetailsManager = new JdbcUserDetailsManager(dataSource);

      // Create initial users if they don't exist
      if (!userDetailsManager.userExists("user")) {
        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder.encode("password"))
            .roles("USER")
            .build();
        userDetailsManager.createUser(user);
      }
      if (!userDetailsManager.userExists("admin")) {
        UserDetails admin = User.builder()
            .username("admin")
            .password(passwordEncoder.encode("adminpass"))
            .roles("ADMIN", "USER")
            .build();
        userDetailsManager.createUser(admin);
      }
      return userDetailsManager;
    }

    // 3. Configure PasswordEncoder
    @Bean
    public PasswordEncoder passwordEncoder() {
      return new BCryptPasswordEncoder();
    }

    // 4. Configure SecurityFilterChain
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
      http
        .authorizeHttpRequests(authorize -> authorize
          .requestMatchers("/admin/**").hasRole("ADMIN") // Example role-based access
          .anyRequest().authenticated()
        )
        .formLogin(form -> form
          .permitAll()
        )
        .logout(logout -> logout
          .permitAll()
        )
        .userDetailsService(userDetailsService(dataSource(), passwordEncoder())); // Explicitly set
      return http.build();
    }
  }
}

Testing Database Auth

Once your application is running, open your browser and navigate to a secured endpoint (e.g., /hello in our example).

You should be redirected to the login page. Try logging in with the credentials inserted into the database:

  • Username: user, Password: password
  • Username: admin, Password: adminpass

Successful login means your database integration is working!

Database Auth Check

Which Spring Security component is essential for loading user data from a database?

Recap & Next Steps

Great job! You've successfully learned how to integrate Spring Security with a database.

  • We understood the benefits of database-backed user management.
  • We explored basic user table schemas.
  • We saw how to use UserDetailsService (specifically JdbcUserDetailsManager) and a PasswordEncoder with a database.
  • We configured Spring Security to use these components.

This is a foundational step for building robust, secure applications. Next, you'll dive deeper into authorization to control what authenticated users can do!

자주 묻는 질문

“데이터베이스 사용자 관리 통합” 강의는 무료인가요?

네 — “데이터베이스 사용자 관리 통합” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Spring Security 6 & JWT Authentication 강의 전체를 잠금 해제할 수 있습니다. Spring Security 6 & JWT Authentication 강의에는 총 4개의 강의가 포함되어 있습니다.

“데이터베이스 사용자 관리 통합”에서 뭘 배우나요?

영속 데이터 소스에 저장된 사용자를 관리하고 인증하도록 Spring Security를 데이터베이스와 통합합니다. 브라우저에서 직접 실행하는 실습 코드로 Spring Security 6 & JWT Authentication을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Spring Security 6 & JWT Authentication을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Spring Security 6 & JWT Authentication은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“데이터베이스 사용자 관리 통합” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Spring Security 6 & JWT Authentication 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Spring Security 6 & JWT Authentication 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 사용자 지정 UserDetailsService 구현
  2. 비밀번호 인코더 이해하기
  3. 데이터베이스 사용자 관리 통합
  4. Granted Authorities를 사용한 역할 기반 권한 부여
← Spring Security 6 & JWT Authentication(으)로 돌아가기