Spring Security 5/OAuth2中JdbcTokenStore的替代方案咨询
兼容Spring Security OAuth2旧JdbcTokenStore与oauth_access_token表的方案
Spring Security 5.x+的OAuth2模块已完成重构,原TokenStore接口被移除,转而基于OAuth2TokenValidator与AuthenticationProvider体系工作。要兼容旧系统的JdbcTokenStore与oauth_access_token表,核心是自定义逻辑读取旧表中的Bearer令牌,将其转换为Spring Security认可的认证对象,具体实现步骤如下:
1. 编写旧令牌数据访问逻辑
复用原有oauth_access_token表结构,创建数据访问类直接查询令牌的有效性、过期时间、用户信息等核心数据:
@Repository public class LegacyJdbcTokenRepository { private final JdbcTemplate jdbcTemplate; public LegacyJdbcTokenRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // 查询令牌基本信息 public Map<String, Object> getTokenDetails(String tokenValue) { String sql = "SELECT user_name, client_id, expires, authentication FROM oauth_access_token WHERE token_id = ?"; return jdbcTemplate.queryForMap(sql, tokenValue); } // 验证令牌是否有效(未过期) public boolean isTokenValid(String tokenValue) { String sql = "SELECT COUNT(1) FROM oauth_access_token WHERE token_id = ? AND expires > NOW()"; Integer count = jdbcTemplate.queryForObject(sql, new Object[]{tokenValue}, Integer.class); return count != null && count > 0; } }
2. 自定义AuthenticationProvider处理旧令牌
实现AuthenticationProvider接口,完成旧令牌的验证逻辑,并生成Spring Security可识别的认证对象:
@Component public class LegacyTokenAuthenticationProvider implements AuthenticationProvider { private final LegacyJdbcTokenRepository tokenRepository; public LegacyTokenAuthenticationProvider(LegacyJdbcTokenRepository tokenRepository) { this.tokenRepository = tokenRepository; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { BearerTokenAuthenticationToken bearerToken = (BearerTokenAuthenticationToken) authentication; String tokenValue = bearerToken.getToken(); // 验证令牌有效性 if (!tokenRepository.isTokenValid(tokenValue)) { throw new BadCredentialsException("Invalid or expired legacy token"); } // 获取令牌关联的用户与客户端信息 Map<String, Object> tokenDetails = tokenRepository.getTokenDetails(tokenValue); String username = (String) tokenDetails.get("user_name"); String clientId = (String) tokenDetails.get("client_id"); // 反序列化旧系统存储的Authentication对象(旧系统用JDK序列化) OAuth2Authentication oAuth2Auth; try (ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) tokenDetails.get("authentication")); ObjectInputStream ois = new ObjectInputStream(bis)) { oAuth2Auth = (OAuth2Authentication) ois.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException("Failed to deserialize legacy authentication data", e); } // 构建用户权限集合 Collection<GrantedAuthority> authorities = oAuth2Auth.getUserAuthentication().getAuthorities(); // 返回标准OAuth2认证对象 return new OAuth2AuthenticationToken( new DefaultOAuth2User(authorities, Map.of("username", username), "username"), authorities, clientId ); } @Override public boolean supports(Class<?> authentication) { return BearerTokenAuthenticationToken.class.isAssignableFrom(authentication); } }
3. 配置SecurityFilterChain注入自定义Provider
修改Spring Security配置,让自定义的认证提供者生效,同时可保留新OAuth2逻辑的兼容性:
@Configuration @EnableWebSecurity public class SecurityConfig { private final LegacyTokenAuthenticationProvider legacyTokenProvider; public SecurityConfig(LegacyTokenAuthenticationProvider legacyTokenProvider) { this.legacyTokenProvider = legacyTokenProvider; } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2 .bearerTokenResolver(new DefaultBearerTokenResolver()) .authenticationManager(authenticationManager()) ); return http.build(); } @Bean public AuthenticationManager authenticationManager() { ProviderManager manager = new ProviderManager(legacyTokenProvider); manager.setEraseCredentials(false); return manager; } }
关键注意事项
- 序列化兼容性:旧系统
authentication字段采用JDK序列化,需确保项目中保留旧版本OAuth2相关类(如OAuth2Authentication、OAuth2Request)的包路径与序列化版本一致,避免反序列化失败。 - 过渡兼容:若需同时支持旧令牌与新JWT令牌,可在
BearerTokenResolver中判断令牌格式(如JWT含.分隔符),路由至不同的认证逻辑。 - 刷新令牌处理:若旧系统需支持令牌刷新,需同理实现
oauth_refresh_token表的查询与刷新逻辑。
内容的提问来源于stack exchange,提问作者Guilherme Silveira
相关产品推荐
相关产品推荐

