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
相关产品推荐
相关产品推荐

