Java框架快速入门: Spring Security+OAuth2之自定义数据库表结构实现认证
2026/9/11 16:27:49 网站建设 项目流程

纲要

  • Spring Security 内建 JDBC 认证的局限
  • 自定义数据库认证的整体思路
  • 项目依赖与工程结构
  • 编写初始化 SQL 脚本(schema.sqldata.sql
  • 控制脚本加载策略:spring.sql.init.mode=embedded
  • 安全配置:基于AuthenticationManagerBuilder自定义查询
  • 启动验证与数据库检查
  • 深入定制:修改表名与字段名
  • 总结

Spring Security 提供了内建的 JDBC 用户存储支持,通过withDefaultSchema()可以自动创建默认的表结构(usersauthorities)。

但真实项目中表结构往往更复杂,表名、字段名可能都有定制需求,直接使用默认结构并不现实。Spring Security 为此提供了非常灵活的扩展点:我们只需提供两条 SQL 查询,框架就能完全适配任何自定义的用户‑权限表。

本文将通过一个完整可运行的 Spring Boot 示例,展示如何从零开始实现数据库认证的定制化。

项目依赖与工程结构

首先创建一个标准的 Spring Boot 项目,引入spring-boot-starter-securityspring-boot-starter-webspring-boot-starter-jdbc以及嵌入式数据库 H2。

<!-- pom.xml --><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version></parent><groupId>com.example</groupId><artifactId>custom-jdbc-auth</artifactId><version>1.0.0</version><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency></dependencies></project>

项目结构如下:

src └── main ├── java │ └── com │ └── example │ ├── CustomJdbcAuthApplication.java │ └── config │ └── SecurityConfig.java └── resources ├── application.properties ├── schema.sql └── data.sql

编写数据库初始化脚本

我们需要自定义两张表:mock_users存储用户信息,mock_authorities存储权限。在resources目录下放置schema.sqldata.sql,Spring Boot 会自动识别并在启动时执行(需结合初始化模式配置)。

-- schema.sqlCREATETABLEIFNOTEXISTSmock_users(usernameVARCHAR(50)NOTNULLPRIMARYKEY,passwordVARCHAR(500)NOTNULL,enabledBOOLEANNOTNULL,nameVARCHAR(100)-- 额外扩展字段,允许为空);CREATETABLEIFNOTEXISTSmock_authorities(idBIGINTAUTO_INCREMENTPRIMARYKEY,usernameVARCHAR(50)NOTNULL,authorityVARCHAR(50)NOTNULL,CONSTRAINTfk_authorities_usersFOREIGNKEY(username)REFERENCESmock_users(username));
-- data.sqlINSERTINTOmock_users(username,password,enabled,name)VALUES('user','{noop}123456',true,'Normal User'),('admin','{noop}admin',true,'Administrator');INSERTINTOmock_authorities(username,authority)VALUES('user','ROLE_USER'),('admin','ROLE_ADMIN');

密码前缀{noop}表示使用明文密码编码器,仅用于演示,生产环境务必使用BCrypt等加密方式。

控制初始化脚本的加载策略

在生产环境我们通常不希望每次启动都执行初始化脚本,以免清空已有数据。Spring Boot 提供了spring.sql.init.mode属性来控制脚本执行时机,使用embedded表示只在嵌入式数据库(如 H2、Derby)时执行,连接外部数据库时则跳过。

# application.properties spring.sql.init.mode=embedded spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.h2.console.enabled=true

这样一来,开发阶段使用内嵌 H2 可自动建表并插入测试数据;切换到 MySQL 等外部数据库时脚本不会执行,保证数据安全。

安全配置:基于自定义查询的 JDBC 认证

核心配置类SecurityConfig中,我们通过AuthenticationManagerBuilderjdbcAuthentication()方法设置数据源及两条关键查询:

  • usersByUsernameQuery:根据用户名查询用户信息,必须返回usernamepasswordenabled三列(顺序及别名必须匹配)。
  • authoritiesByUsernameQuery:根据用户名查询权限列表,必须返回usernameauthority两列。

即使我们使用了与默认不同的表名和字段名,只要 SQL 查询的返回列别名正确,框架就能完全适配。

packagecom.example.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.crypto.factory.PasswordEncoderFactories;importorg.springframework.security.crypto.password.PasswordEncoder;importorg.springframework.security.web.SecurityFilterChain;importjavax.sql.DataSource;importstaticorg.springframework.security.config.Customizer.withDefaults;@Configuration@EnableWebSecuritypublicclassSecurityConfig{@BeanpublicSecurityFilterChainfilterChain(HttpSecurityhttp)throwsException{http.authorizeHttpRequests(authz->authz.requestMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated()).httpBasic(withDefaults());returnhttp.build();}@BeanpublicPasswordEncoderpasswordEncoder(){// 使用委托密码编码器,支持 {noop}、{bcrypt} 等前缀returnPasswordEncoderFactories.createDelegatingPasswordEncoder();}// 通过注入 AuthenticationManagerBuilder 并调用 jdbcAuthentication 进行自定义// 更推荐的方式:直接在 configure(AuthenticationManagerBuilder) 中配置// 此处采用新的风格:通过注入 DataSource 并以 Bean 方式配置// 实际可根据习惯选用@BeanpublicvoidconfigureGlobal(AuthenticationManagerBuilderauth,DataSourcedataSource)throwsException{auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("SELECT username, password, enabled FROM mock_users WHERE username = ?").authoritiesByUsernameQuery("SELECT username, authority FROM mock_authorities WHERE username = ?").passwordEncoder(passwordEncoder());}}

启动类CustomJdbcAuthApplication.java非常简单:

packagecom.example;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassCustomJdbcAuthApplication{publicstaticvoidmain(String[]args){SpringApplication.run(CustomJdbcAuthApplication.class,args);}}

启动验证

启动应用后,Spring Boot 会自动执行schema.sqldata.sql,在 H2 内存库中创建MOCK_USERSMOCK_AUTHORITIES表并插入数据。通过浏览器访问http://localhost:8080/h2-console,使用 JDBC URLjdbc:h2:mem:testdb连接,可以查看到两张表的内容。

使用 curl 测试认证:

# 访问受保护资源,使用 user/123456 认证curl-uuser:123456 http://localhost:8080/any-path

若配置了/admin路径需要 ADMIN 角色,使用admin:admin即可访问。

深入定制:修改表名与字段名

上述配置中,SQL 返回列已经使用了别名来匹配框架的预期名称。如果实际业务表中用户名字段为login_name,密码字段为pwd,状态字段为active,只需调整usersByUsernameQuery

SELECTlogin_nameASusername,pwdASpassword,activeASenabledFROMmy_usersWHERElogin_name=?

同理,权限表若字段不同,也可以通过别名映射。这便是 Spring Security JDBC 认证最灵活的定制方式,无需重写UserDetailsService,仅靠两条 SQL 即可接入任何遗留系统的用户数据。

总结

本文从 Spring Security 默认 JDBC 存储的局限出发,完整演示了如何通过自定义schema.sqldata.sql初始化表结构,结合spring.sql.init.mode=embedded控制脚本执行,并在安全配置中使用两条查询语句适配任意用户‑权限表。

这种方式不仅适用于纯 JDBC 环境,当与 MyBatis 等框架配合时也同样简便,为后续深度定制(如整合 JPA 实现统一风格)打下了良好基础。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询