HttpClient 5.3.1弃用NTLM后,如何通过头部实现认证?
处理Apache HttpClient 5.3.1中的NTLM认证问题
一、继续使用HttpClient内置的NTLM支持(尽管已弃用)
HttpClient 5.3.1仅将NTLM认证标记为弃用,并未移除相关实现,所以你依然可以用它适配企业的NTLM认证需求,只需确保引入对应的NTLM模块依赖(Maven示例):
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5-ntlm</artifactId> <version>5.3.1</version> </dependency>
然后配置HttpClient,注册NTLM凭证并启用自动挑战处理:
// 创建凭证提供者,添加NTLM凭证 CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials( AuthScope.ANY, new NTCredentials("你的用户名", "你的密码", "工作站名称", "企业域名") ); // 构建HttpClient,启用自动认证 CloseableHttpClient httpClient = HttpClients.custom() .setDefaultCredentialsProvider(credsProvider) .build();
HttpClient会自动检测401响应中的NTLM挑战,自动生成并发送对应的Authorization头,无需手动处理握手流程。
二、手动操作请求头实现NTLM认证(借助JCIFS库)
如果不想依赖HttpClient的弃用API,可以用JCIFS库手动生成NTLM认证令牌,直接操作请求头完成认证。
- 先添加JCIFS依赖(Maven示例):
<dependency> <groupId>org.codelibs</groupId> <artifactId>jcifs</artifactId> <version>2.1.35</version> </dependency>
- 手动处理NTLM三次握手流程:
NTLM认证需要三次交互(Type1请求→Type2挑战→Type3响应),完整实现代码如下:
CloseableHttpClient httpClient = HttpClients.createDefault(); String targetUrl = "http://你的企业服务地址"; // 第一步:发送Type1请求(无认证头,触发服务器返回Type2挑战) HttpGet type1Request = new HttpGet(targetUrl); CloseableHttpResponse type2Response = httpClient.execute(type1Request); if (type2Response.getCode() == HttpStatus.SC_UNAUTHORIZED) { // 提取NTLM Type2挑战内容 String ntlmChallenge = null; for (Header header : type2Response.getHeaders("WWW-Authenticate")) { if (header.getValue().startsWith("NTLM ")) { ntlmChallenge = header.getValue().substring(5); break; } } if (ntlmChallenge != null) { // 第二步:用JCIFS生成Type3响应令牌 NtlmPasswordAuthentication ntlmAuth = new NtlmPasswordAuthentication( "企业域名", "你的用户名", "你的密码" ); byte[] challengeBytes = Base64.getDecoder().decode(ntlmChallenge); byte[] type3Bytes = ntlmAuth.getType3Message(challengeBytes).toByteArray(); String type3Response = Base64.getEncoder().encodeToString(type3Bytes); // 第三步:发送携带Type3响应的请求 HttpGet type3Request = new HttpGet(targetUrl); type3Request.addHeader("Authorization", "NTLM " + type3Response); CloseableHttpResponse finalResponse = httpClient.execute(type3Request); // 处理最终响应(示例) System.out.println("响应状态码:" + finalResponse.getCode()); String responseBody = EntityUtils.toString(finalResponse.getEntity()); System.out.println("响应内容:" + responseBody); finalResponse.close(); } } type2Response.close(); httpClient.close();
注意事项
- 内置NTLM支持虽可用,但毕竟已被弃用,建议和企业IT团队沟通,逐步迁移到Kerberos等更安全的认证方案
- 手动实现时要注意Base64编码的正确性,以及NTLM消息格式的兼容性,不同服务器的挑战可能有细微差异
- 大规模企业环境下,建议使用HttpClient连接池复用连接,提升请求效率
内容的提问来源于stack exchange,提问作者Allan
相关产品推荐
相关产品推荐

