You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security OAuth2密码模式:提取请求中用户名密码做数据库校验

嘿,刚好我之前在做Spring Security OAuth2密码模式的时候,也遇到过一模一样的需求——把用户的用户名密码从请求里提取出来和数据库校验,而不是用配置文件硬编码。既然你已经搞定了客户端凭证的校验,那接下来只需要调整用户认证的部分就行,我给你拆解成配置和代码两部分来说:

一、application.properties 配置调整

首先,你可以删掉之前硬编码的用户信息,添加上数据库连接配置(如果还没加的话),客户端相关的配置保留你已经实现的部分即可:

# 数据库连接配置(根据你的数据库类型调整)
spring.datasource.url=jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.username=db_user
spring.datasource.password=db_pwd
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# OAuth2客户端配置(你已实现的部分,直接保留)
spring.security.oauth2.authorization.client.registration.testClient.client-id=testClient
spring.security.oauth2.authorization.client.registration.testClient.client-secret=123456
spring.security.oauth2.authorization.client.registration.testClient.authorization-grant-type=password
spring.security.oauth2.authorization.client.registration.testClient.scopes=read,write
二、核心认证服务类改造

1. 实现自定义UserDetailsService

这个类是用来从数据库查询用户信息的核心,替换默认的内存用户校验逻辑。我用JdbcTemplate举个例子(用MyBatis的话逻辑完全类似):

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final JdbcTemplate jdbcTemplate;

    // 构造注入JdbcTemplate
    public CustomUserDetailsService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据你的数据库表结构调整SQL,查询用户名、加密后的密码、账号状态等信息
        String sql = "SELECT username, password, enabled FROM sys_user WHERE username = ?";
        User user = jdbcTemplate.queryForObject(sql, new Object[]{username},
                (rs, rowNum) -> new User(
                        rs.getString("username"),
                        rs.getString("password"),
                        rs.getBoolean("enabled"),
                        true, true, true, // 账号过期、锁定、凭证过期状态,根据业务调整
                        AuthorityUtils.createAuthorityList("ROLE_USER") // 用户权限,按需配置
                ));

        if (user == null) {
            throw new UsernameNotFoundException("用户不存在: " + username);
        }
        return user;
    }
}

2. 调整授权服务器配置类

修改你的AuthorizationServerConfig,把自定义的UserDetailsService和AuthenticationManager注入进去,让密码模式使用数据库校验逻辑:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    private final AuthenticationManager authenticationManager;
    private final CustomUserDetailsService userDetailsService;
    private final PasswordEncoder passwordEncoder;
    private final ClientDetailsService clientDetailsService;

    // 构造注入所需Bean
    public AuthorizationServerConfig(AuthenticationManager authenticationManager,
                                     CustomUserDetailsService userDetailsService,
                                     PasswordEncoder passwordEncoder,
                                     ClientDetailsService clientDetailsService) {
        this.authenticationManager = authenticationManager;
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
        this.clientDetailsService = clientDetailsService;
    }

    // 客户端配置(你已实现的部分,保留即可)
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }

    // 重点:配置授权端点,启用数据库用户校验
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager) // 密码模式必须配置这个Bean
                .userDetailsService(userDetailsService); // 替换默认的用户信息来源
    }

    // 可选:配置令牌存储(生产环境建议用JdbcTokenStore或JWT)
    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
}

3. 补充WebSecurity配置

别忘了配置AuthenticationManager和PasswordEncoder的Bean,上面的授权服务器配置需要依赖它们:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 这里要和数据库存储的密码加密方式一致,比如BCrypt
        return new BCryptPasswordEncoder();
    }
}
逻辑说明

当请求带着username=Test&password=Test@123过来时,OAuth2的密码模式会自动调用我们的CustomUserDetailsService从数据库查询用户信息,然后用PasswordEncoder校验请求里的密码和数据库中加密后的密码是否匹配,完成整个用户认证流程。

内容的提问来源于stack exchange,提问作者Sylar_781227

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:06:10