的确快有好一段时间没有在博客里写文了。今年大量的精力都忙在了完成工作任务,而且我的团队在过去一段时间经历战略转变、裁员和项目调整,十分动荡。临近 Holiday Season,业务基本都停了以求稳定,我总算是闲下来了。
在微软这公司里面做开发,绝对绕不开的就是 Azure 云环境。我们从 OLTP 到 OLAP,几乎所有项目的数据库方案都使用 SQL Server。可惜这个数据库产品在国内科技公司并没有什么市场。资料很少并且高度依赖微软给的技术文档。
我维护的一块后端服务本基于某开源工程,其设计时采用的是经典的 SpringBoot + MyBatis + MySQL 架构,部署到 Azure 云环境需要对持久层 MySQL 做改造,换成 Azure SQL Database 产品。
按照 JDBC 的规范,Druid 是能兼容 SQL Server 产品的,但某些定制化的功能,如 Entra ID 认证 (原 Azure Active Directory 认证),并不原生支持。
我所在的团队从两年前开始已经明确禁止本地认证(含密码、密钥和证书等),若要对 SQL Server 做认证必须使用 Entra ID 登陆。综上,我需要对 Druid + SQL Server 做 Entra ID 认证的改造和适配。
查阅微软给的官方资料,有这么一个功能引起我的注意:
accessTokenCallbackClass |
(Version 12.4+) The name of the callback-implementing class to be used with access token callback. |
构建 SQL Server JDBC Connection 对象时,可以指定一个获取 Access Token 的回调函数。在 JDBC 驱动开始连接到数据库时,会触发这个函数,通过回调返回值向程序返回一个 Entra ID 的 Access Token,完成登陆。
因此得到了这么一个方案:设置 Druid 的 Connection URL 配置,指定回调函数,在回调函数里借住 Azure SDK,获取一个 Entra ID Credential,之后再从该 Credential 取一个登陆 SQL Server 使用的 Access Token。这样就完成了 Druid 的 Entra ID 登陆/认证。
Druid 配置:
application-sqlserver.yaml
spring:
datasource:
druid:
url: jdbc:sqlserver://${example.database.ip}:${example.database.port};databaseName=${example.database.name};accessTokenCallbackClass=com.example.druid.EntraIdLoginCallback;encrypt=${example.database.useSSL};trustServerCertificate=true
username: ""
password: ""
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
* 使用 Entra ID + Access Token 登陆的时候,JDBC 用户名和密码字段必须为 null/空白。
上面的配置设定了 com.example.druid.EntraIdLoginCallback 类作为 Access Token 的回调函数类。接下来需要在包中实现这个类以及它的 getAccessToken() 函数。
EntraIdLoginCallback.java
package example;
import com.microsoft.sqlserver.jdbc.SQLServerAccessTokenCallback;
import com.microsoft.sqlserver.jdbc.SqlAuthenticationToken;
import java.util.Date;
public class EntraIdLoginCallback implements SQLServerAccessTokenCallback {
@Override
public SqlAuthenticationToken getAccessToken(String spn, String stsurl) {
// TODO: Acquire an access token (Azure SDK)
String token = "<-- Set your access token here -->";
String date = new Date().toString(); // <-- Set your token expiry date here -->
return new SqlAuthenticationToken(token, date);
}
}
接下来只需要在回调函数里实现获取一个 Access Token 逻辑,如借助 azure-identity SDK,作为函数返回值,就实现了 Entra ID 的登陆认证。
下面是一些调试日志:
2025-10-18 04:09:38,205 [ERROR] c.a.d.p.DruidDataSource.init - init datasource error, url: jdbc:sqlserver://xxxxxxxx.database.windows.net:1433;databaseName=master;accessTokenCallbackClass=com.example.druid.EntraIdLoginCallback;encrypt=false;trustServerCertificate=true
com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user '<token-identified principal>'. ClientConnectionId:54a6b821-aa84-4a56-8ee8-0902a1ab8ae5
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:278) ~[mssql-jdbc-13.2.0.jre8.jar:?]
注意关键词 <token-identified principal>,说明此时 SQL Server JDBC 驱动在连接到服务器使用 Token 认证方式。
参考资料
Connect using Microsoft Entra authentication – Microsoft Learn
0 条评论