OkHttp源码学习之Authenticator

OkHttp 中,Authenticator 是一个用于处理 HTTP 认证(Authentication)的接口,主要用于在服务端要求身份验证时自动提供凭据(如用户名和密码)。

Authenticator 的作用

  1. 处理 HTTP 401(Unauthorized)和 407(Proxy Authentication Required)状态码

    当服务器或代理返回这些状态码时,Authenticator 会被调用以提供认证信息。

  2. 自动重试请求
    OkHttp 使用 Authenticator 生成包含认证头的请求,并自动重试。这简化了开发流程,无需手动处理这些情况。

  3. 支持多种认证方式

    通过自定义实现,可以支持 BasicBearer 或其他定制的认证方式。

Authenticator 的实现

Authenticator 是一个函数式接口,定义了以下方法:

less 复制代码
java
复制代码
public interface Authenticator {
    Request authenticate(@Nullable Route route, Response response) throws IOException;
}

参数说明

  • route:提供网络请求的路由信息(如目标主机和端口)。
  • response:包含服务端的响应信息,通常包含 WWW-AuthenticateProxy-Authenticate 头,用于指示所需的认证方式。

返回值

  • 返回一个新的 Request 对象,其中包含了认证头(AuthorizationProxy-Authorization)。
  • 返回 null 表示放弃认证,OkHttp 不会重试请求。

默认 Authenticator

  • Authenticator.NONE :表示不处理认证,返回 null

常见场景与实现

1. Basic Authentication

kotlin 复制代码
val basicAuthenticator = Authenticator { _, response ->
    val credentials = Credentials.basic("username", "password")
    response.request.newBuilder()
        .header("Authorization", credentials)
        .build()
}

val client = OkHttpClient.Builder()
    .authenticator(basicAuthenticator)
    .build()

2. Token Authentication

当需要在请求中添加 Bearer Token 或自定义的认证信息时:

kotlin 复制代码
val tokenAuthenticator = Authenticator { _, response ->
    val token = "your-token-here"  // Replace with logic to retrieve token
    response.request.newBuilder()
        .header("Authorization", "Bearer $token")
        .build()
}

val client = OkHttpClient.Builder()
    .authenticator(tokenAuthenticator)
    .build()

3. Proxy Authentication

针对代理服务器的认证:

kotlin 复制代码
val proxyAuthenticator = Authenticator { _, response ->
    val credentials = Credentials.basic("proxyUser", "proxyPassword")
    response.request.newBuilder()
        .header("Proxy-Authorization", credentials)
        .build()
}

val client = OkHttpClient.Builder()
    .proxyAuthenticator(proxyAuthenticator)
    .build()

重要注意事项

  1. 避免无限循环

    • 如果认证失败,服务端可能继续返回 401407 状态码,这个时候我们需要添加退避策略或者控制重试次数。
    • 确保在 Authenticator 中检查重试次数或响应的请求历史,以避免无限重试。
    kotlin 复制代码
    val limitedRetryAuthenticator = Authenticator { _, response ->
        if (response.request.header("Authorization") != null) {
            // 防止无限重试
            null
        } else {
            val credentials = Credentials.basic("username", "password")
            response.request.newBuilder()
                .header("Authorization", credentials)
                .build()
        }
    }
  2. 线程安全性

    • 如果 Authenticator 需要访问共享资源(如刷新令牌),确保实现是线程安全的。
  3. 避免将敏感信息硬编码

    • 使用安全存储(如 Android 的 Keystore)来存储凭据。
相关推荐
今天多喝热水1 分钟前
SpEL(Spring Expression Language) 表达式
java·后端·spring
wasp5202 分钟前
Hudi 客户端实现分析
java·开发语言·人工智能·hudi
学海无涯书山有路2 分钟前
Android LiveData + MVVM 新手入门教程(基于 XML+Java)
android·xml·java
Hello.Reader3 分钟前
Flink 2.0 从 flink-conf.yaml 到 config.yaml 的正确打开方式(含迁移与最佳实践)
java·前端·flink
李慕婉学姐4 分钟前
【开题答辩过程】以《基于uni-app的手账记录小程序的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·小程序·uni-app
晚霞的不甘5 分钟前
Flutter for OpenHarmony:注入灵魂:购物车的数据驱动与状态管理实战
android·前端·javascript·flutter·前端框架
福大大架构师每日一题5 分钟前
milvus v2.6.9 发布:支持主键搜索、段重开机制、日志性能全面提升!
android·java·milvus
独自破碎E5 分钟前
【滑动窗口】最长无重复子数组
java·开发语言
GIOTTO情5 分钟前
Infoseek 媒介投放系统技术实现:基于与辉同行风波的风险防控架构设计
java·架构·媒体
木井巳6 分钟前
【Java】数据类型及运算符重点总结
java·开发语言