0Pricing
Spring Security 6 & JWT Authentication · 课时

集成数据库用户管理

将 Spring Security 与数据库集成,管理并验证持久化数据源中的用户。

集成数据库用户管理 是 CoddyKit 上的免费 Spring Security 6 & JWT Authentication 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 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!

常见问题解答

「集成数据库用户管理」课时是免费的吗?

是的 — 「集成数据库用户管理」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Spring Security 6 & JWT Authentication 课程的其余内容,请升级到 CoddyKit PRO。 Spring Security 6 & JWT Authentication 课程共包含 4 节课。

「集成数据库用户管理」这节课中我会学到什么?

将 Spring Security 与数据库集成,管理并验证持久化数据源中的用户。 你通过在浏览器中直接运行的动手代码来练习 Spring Security 6 & JWT Authentication,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Spring Security 6 & JWT Authentication 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Spring Security 6 & JWT Authentication 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「集成数据库用户管理」课时需要多长时间?

大多数 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