1. 概述

本文将介绍如何使用 Java 标准库中的 HttpUrlConnection 类实现 HTTP 请求的认证功能。虽然现在很多人更倾向于使用 HttpClient 或 OkHttp,但在某些轻量级场景或受限环境中,HttpUrlConnection 依然是一个简单粗暴且无需引入第三方依赖的选择。

2. HTTP 认证机制简介

在 Web 应用中,服务器通常会要求客户端提供身份凭证。如果未提供或凭证无效,服务器将返回 HTTP 401 Unauthorized 状态码。

HTTP 支持多种认证方案(authentication schemes),它们在安全性和实现复杂度上各有不同。常见的有以下几种:

  • Basic:基础认证,用户名密码 Base64 编码后传输(本文重点)
  • Digest:摘要认证,通过哈希算法和服务器随机数(nonce)防止明文暴露
  • Bearer:承载令牌认证,常用于 OAuth 2.0 场景,携带 access token

⚠️ 注意:Basic 认证本身不安全,必须配合 HTTPS(TLS)使用,否则相当于在网络上传输明文密码。

3. Basic 认证原理

Basic 认证的核心是通过 Authorization 请求头传递编码后的凭证:

GET / HTTP/1.1
Authorization: Basic dXNlcjpwYXNzd29yZA==

生成方式非常直接:

basic(user, pass) = Base64.encode(user + ":" + pass)

例如,用户名 alice,密码 secret123,拼接为 alice:secret123,Base64 编码后得到 YWxpY2U6c2VjcmV0MTIz

最终请求头就是:

Authorization: Basic YWxpY2U6c2VjcmV0MTIz

📌 再次强调
虽然传输的是“编码”而非“加密”,但 Base64 可逆,等同于明文。因此 ❌ 切勿在非 HTTPS 环境下使用 Basic 认证

4. 手动配置 HttpUrlConnection 实现认证

要使用 HttpUrlConnection 发起带认证的请求,步骤如下:

步骤 1:创建连接

URL url = new URL("https://api.example.com/user");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

步骤 2:构造 Authorization 头

String user = "alice";
String password = "secret123";

String auth = user + ":" + password;
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8));
String authHeaderValue = "Basic " + new String(encodedAuth);

✅ Java 8+ 推荐使用 java.util.Base64.getEncoder(),替代已废弃的 Apache Commons Codec。

步骤 3:设置请求头

connection.setRequestProperty("Authorization", authHeaderValue);

步骤 4:发送请求并获取响应

int responseCode = connection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {
    // 认证成功,处理响应
} else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
    // 认证失败,检查凭证
}

小结:这种方式适用于单次或少量请求,但每个连接都需要手动设置 header,略显重复。

5. 使用 Java Authenticator 全局配置认证

如果你希望一次配置,全局生效,可以使用 java.net.Authenticator 类。它会在每次遇到 401 响应时自动尝试认证。

实现自定义 Authenticator

private static class BasicAuthenticator extends Authenticator {
    private final String username;
    private final String password;

    public BasicAuthenticator(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(username, password.toCharArray());
    }
}

注册为默认认证器

Authenticator.setDefault(new BasicAuthenticator("alice", "secret123"));

发起请求(无需手动设 header)

URL url = new URL("https://api.example.com/user");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int responseCode = connection.getResponseCode(); // 自动处理认证

优点

  • 全局生效,减少重复代码
  • 自动响应 401 挑战(challenge)

⚠️ 注意点

  • Authenticator 是 JVM 全局单例,影响所有 HttpUrlConnection 请求
  • 多线程环境下需谨慎使用,避免认证信息污染
  • 不支持细粒度控制(比如不同域名不同凭证),需自行判断上下文(可通过 getRequestingSite()getRequestingPort() 等方法区分)

6. 总结

本文介绍了两种使用 HttpUrlConnection 实现 HTTP Basic 认证的方式:

方式 适用场景 是否推荐
手动设置 Authorization header 单次请求、精准控制 ✅ 推荐
使用 Authenticator 全局设置 多请求、统一凭证 ⚠️ 谨慎使用

📌 关键建议

  • 始终配合 HTTPS 使用 Basic 认证
  • 生产环境优先考虑 OAuth2 Bearer Token 或更安全的方案
  • 若需更高性能和现代 API,建议迁移到 HttpClient(Java 11+)

示例代码已上传至 GitHub:https://github.com/example/java-networking-demo


原始标题:Authentication with HttpUrlConnection