如何不重启服务刷新HikariDataSource连接SQL Server的过期AccessToken
解决方案
根因说明
你在初始化HikariDataSource Bean时一次性获取访问令牌写入静态配置,后续所有新连接创建都会复用该令牌,Azure AD令牌默认有效期仅1小时,过期后没有自动更新机制,就会触发登录失败报错。
实现步骤
1. 版本依赖确认
确保使用的com.microsoft.sqlserver:mssql-jdbc版本≥10.2.0,该版本开始支持accessTokenCallback配置,可在每次新建连接时动态获取令牌。同时com.microsoft.azure:msal4j保持最新稳定版本即可。
2. 复用MSAL令牌缓存
将MSAL的ConfidentialClientApplication实例注册为单例Bean,MSAL内置令牌缓存会自动处理令牌刷新,无需每次请求Azure AD接口,只有令牌快过期时才会自动调用接口拉取新令牌。
@Bean public ConfidentialClientApplication confidentialClientApplication( @Value("${azure.ad.client-id}") String clientId, @Value("${azure.ad.client-secret}") String clientSecret, @Value("${azure.ad.tenant-id}") String tenantId ) throws MalformedURLException { return ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(clientSecret)) .authority("https://login.microsoftonline.com/" + tenantId) .build(); }
3. 封装令牌获取回调
封装令牌获取逻辑,每次调用时优先从MSAL缓存中取有效令牌:
@Autowired private ConfidentialClientApplication clientApplication; @Value("${azure.ad.sql.scope}") // 格式通常为 https://database.windows.net/.default private String sqlScope; private Supplier<String> accessTokenSupplier() { return () -> { Set<String> scopes = Collections.singleton(sqlScope); ClientCredentialParameters parameters = ClientCredentialParameters.builder(scopes).build(); try { IAuthenticationResult result = clientApplication.acquireToken(parameters).join(); return result.accessToken(); } catch (Exception e) { throw new RuntimeException("获取Azure AD访问令牌失败", e); } }; }
4. 修改Hikari数据源配置
删除原有静态写入accessToken的逻辑,改为配置accessTokenCallback,同时设置连接最大生命周期小于令牌有效期,避免连接池中存在使用过期令牌的存活连接:
@Bean public DataSource dataSource() { HikariConfig config = new HikariConfig(); // 基础配置保持不变:JDBC地址、连接池大小、超时时间等 config.setJdbcUrl("你的SQL Server JDBC连接串"); config.setPoolName("SqlserverCP"); config.setConnectionTimeout(30000); // 核心配置1:配置令牌回调,每次新建连接时动态获取最新有效令牌 config.getDataSourceProperties().put("accessTokenCallback", accessTokenSupplier()); // 核心配置2:连接最大生命周期设为55分钟,短于Azure AD令牌默认1小时有效期 config.setMaxLifetime(3300000); // 可选配置:借出连接前校验有效性,进一步避免无效连接返回给业务 config.setTestOnBorrow(true); config.setConnectionTestQuery("SELECT 1"); return new HikariDataSource(config); }
原理说明
修改后每次JDBC驱动创建新连接时,都会自动调用配置的令牌回调获取最新的有效令牌完成认证,配合Hikari的连接生命周期管理,旧连接会在令牌过期前被自动销毁,全程无需重启服务,也不需要手动处理令牌刷新逻辑。
内容的提问来源于stack exchange,提问作者KikeSP
相关产品推荐
相关产品推荐

