如何在Quarkus中实现NTLMv1认证以调用SharePoint REST API
1. 依赖引入
首先在项目构建配置中添加必要依赖,以Maven为例:
<dependencies> <!-- Quarkus响应式REST客户端核心依赖 --> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-rest-client-reactive</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-rest-client-reactive-jackson</artifactId> </dependency> <!-- NTLM认证支持依赖 --> <dependency> <groupId>jcifs</groupId> <artifactId>jcifs</artifactId> <version>1.3.19</version> </dependency> </dependencies>
2. 基础配置
在application.properties中添加SharePoint连接和NTLM认证相关配置:
# SharePoint站点基础地址 quarkus.rest-client.sharepoint-api.url=https://your-sharepoint-site-url # NTLM认证配置 sharepoint.auth.domain=YOUR_AD_DOMAIN sharepoint.auth.username=your_account sharepoint.auth.password=your_password sharepoint.auth.workstation=YOUR_WORKSTATION_NAME # Form Digest缓存过期预留时间(秒,避免临界时间请求失败) sharepoint.digest.expire-reserve=10
3. 核心功能实现
3.1 Form Digest缓存实体
public class FormDigestInfo { private String digestValue; private long expireTimestamp; // 构造器、getter、setter省略 public boolean isExpired() { return System.currentTimeMillis() > expireTimestamp; } }
3.2 NTLM认证+自动刷新Digest的请求拦截器
import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.ext.Provider; import jcifs.ntlmssp.NtlmFlags; import jcifs.ntlmssp.Type1Message; import org.eclipse.microprofile.config.inject.ConfigProperty; import java.util.Base64; @Provider @ApplicationScoped public class SharePointAuthFilter implements ClientRequestFilter { @ConfigProperty(name = "sharepoint.auth.domain") String domain; @ConfigProperty(name = "sharepoint.auth.username") String username; @ConfigProperty(name = "sharepoint.auth.password") String password; @ConfigProperty(name = "sharepoint.auth.workstation") String workstation; @ConfigProperty(name = "sharepoint.digest.expire-reserve") int expireReserve; private FormDigestInfo cachedDigest; @Override public void filter(ClientRequestContext requestContext) { // 注入NTLM认证头 addNtlmAuthHeader(requestContext); // 非Digest获取请求自动携带有效Digest头 if (!requestContext.getUri().getPath().contains("_api/contextinfo")) { requestContext.getHeaders().add("X-RequestDigest", getValidDigest()); } } private void addNtlmAuthHeader(ClientRequestContext context) { // 生成NTLMv1 Type1消息 Type1Message type1 = new Type1Message(NtlmFlags.NTLMSSP_NEGOTIATE_NTLM | NtlmFlags.NTLMSSP_NEGOTIATE_UNICODE, domain, workstation); String type1Str = Base64.getEncoder().encodeToString(type1.toByteArray()); context.getHeaders().add("Authorization", "NTLM " + type1Str); // Quarkus REST Client配合JCIFS可自动完成后续NTLM握手流程,无需手动处理Type2/Type3消息交互 } private String getValidDigest() { if (cachedDigest == null || cachedDigest.isExpired()) { cachedDigest = requestNewDigest(); } return cachedDigest.getDigestValue(); } private FormDigestInfo requestNewDigest() { // 调用/_api/contextinfo接口获取最新Digest,解析返回结果构造FormDigestInfo // 过期时间计算规则:当前时间 +(返回的超时秒数 - 预留秒数)* 1000 // 具体解析逻辑可根据接口实际返回结构实现 } }
3.3 SharePoint REST Client定义
import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @RegisterRestClient(configKey = "sharepoint-api") @RegisterProvider(SharePointAuthFilter.class) public interface SharePointClient { // 获取Form Digest接口 @POST @Path("/_api/contextinfo") String getContextInfo(); // 自定义文件夹读写相关接口,例如创建文件夹、读取文件列表、上传文件等 }
4. 注意事项
- NTLMv1协议安全性较低,仅建议在内网隔离环境使用,生产环境优先升级到NTLMv2或OAuth 2.0认证
- Form Digest的缓存逻辑需做好并发控制,避免多线程同时触发刷新请求
- 配置的域账号需要提前分配对应SharePoint站点文件夹的读写权限,避免权限不足导致操作失败
- 如果使用非响应式REST客户端,可替换对应依赖,认证逻辑通用
内容的提问来源于stack exchange,提问作者lopah elision
相关产品推荐
相关产品推荐

