You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JDK HttpClient中实现curl --ntlm参数对应的NTLM身份认证

问题描述

我对各类HTTP上层协议并不算十分精通,目前我可以通过以下curl命令访问公司的某一个API:

curl  --http1.1 --ntlm -u 'user:pass' 'MY_URL'

该命令可以正常运行,请注意命令中指定了--ntlm参数。
我现在尝试用http-jdk-client复现相同的请求逻辑,代码如下:

var client = HttpClient.newBuilder()
            .authenticator(new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(<user>, <pass>.toCharArray());
                }
            })
            .sslContext(sslContext()) // an SSL Context that trusts everyone
            .version(HttpClient.Version.HTTP_1_1)
            .build();
    var request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .build();
    client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::body)
            .thenAccept(System.out::println)
            .join();

这段代码运行后返回401错误。
如果我使用相同的curl命令但去掉--ntlm参数,也会得到同样的401错误。因此我判断需要在JDK客户端中复现--ntlm参数的效果,请问有什么相关的思路或者解决方案吗?谢谢。


解决方案

原因说明

JDK自带的HttpClient默认未开启NTLM认证支持,仅配置基础的Authenticator无法触发NTLM的三次握手认证流程,因此会返回401未授权错误。

方案1:开启JDK HttpClient的NTLM支持

通过配置系统属性启用NTLM认证,可直接适配现有代码逻辑:

  1. 代码初始化阶段添加全局配置,开启NTLM认证支持:
// 测试环境可直接开启所有域名的NTLM透明认证
System.setProperty("jdk.http.ntlm.transparentAuth", "allHosts");
// 禁用默认的NTLM认证拦截规则
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
System.setProperty("jdk.http.auth.proxying.disabledSchemes", "");
  1. 调整账号格式:如果是域账号,PasswordAuthentication的用户名字段需要填写域名\\用户名格式,比如"COMPANY\\zhangsan",无域名则直接填用户名即可。

调整后的完整代码如下:

// 全局配置放到代码初始化位置
System.setProperty("jdk.http.ntlm.transparentAuth", "allHosts");
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
System.setProperty("jdk.http.auth.proxying.disabledSchemes", "");

var client = HttpClient.newBuilder()
        .authenticator(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                // 域账号格式:域名\\用户名,无域名直接填用户名
                return new PasswordAuthentication("your_username", "your_password".toCharArray());
            }
        })
        .sslContext(sslContext())
        .version(HttpClient.Version.HTTP_1_1)
        .followRedirects(HttpClient.Redirect.NORMAL)
        .build();
var request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
        .thenApply(HttpResponse::body)
        .thenAccept(System.out::println)
        .join();

方案2:使用Apache HttpClient 5(兼容性更好)

如果JDK自带的HttpClient方案不稳定,推荐使用原生支持NTLM认证的Apache HttpClient 5,企业场景下兼容性更高:

  1. 引入Maven依赖:
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.2.1</version>
</dependency>
  1. 实现代码示例:
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.NTCredentials;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.core5.http.io.entity.EntityUtils;

// 配置NTLM凭证
// 参数依次为:用户名、密码、本地主机名(可填null)、域名(无域则填空字符串)
NTCredentials credentials = new NTCredentials("your_username", "your_password".toCharArray(), null, "your_domain");
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
// 替换为你API的实际域名和端口,HTTPS默认端口443,HTTP默认端口80
credentialsProvider.setCredentials(new AuthScope("your_api_host", 443), credentials);

// 构建HTTP客户端
try (CloseableHttpClient httpClient = HttpClients.custom()
        .setDefaultCredentialsProvider(credentialsProvider)
        .setSSLContext(sslContext())
        .build()) {
    HttpGet request = new HttpGet("YOUR_API_URL");
    httpClient.execute(request, response -> {
        System.out.println("响应状态码:" + response.getCode());
        System.out.println("响应内容:" + EntityUtils.toString(response.getEntity()));
        return null;
    });
}

注意事项

  • NTLM是连接绑定的认证协议,需要保证客户端开启连接复用,不要每次请求都新建客户端实例
  • 如果是生产环境使用方案1,建议将jdk.http.ntlm.transparentAuth设为trustedHosts,同时配置jdk.http.ntlm.trustedHosts为你公司API的域名列表,避免安全风险

内容的提问来源于stack exchange,提问作者Eugene

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 00:48:05