在 OkHttp
中,Authenticator
是一个用于处理 HTTP 认证(Authentication)的接口,主要用于在服务端要求身份验证时自动提供凭据(如用户名和密码)。
Authenticator
的作用
-
处理 HTTP 401(Unauthorized)和 407(Proxy Authentication Required)状态码 :
当服务器或代理返回这些状态码时,
Authenticator
会被调用以提供认证信息。 -
自动重试请求 :
OkHttp
使用Authenticator
生成包含认证头的请求,并自动重试。这简化了开发流程,无需手动处理这些情况。 -
支持多种认证方式 :
通过自定义实现,可以支持
Basic
、Bearer
或其他定制的认证方式。
Authenticator
的实现
Authenticator
是一个函数式接口,定义了以下方法:
less
java
复制代码
public interface Authenticator {
Request authenticate(@Nullable Route route, Response response) throws IOException;
}
参数说明
route
:提供网络请求的路由信息(如目标主机和端口)。response
:包含服务端的响应信息,通常包含WWW-Authenticate
或Proxy-Authenticate
头,用于指示所需的认证方式。
返回值
- 返回一个新的
Request
对象,其中包含了认证头(Authorization
或Proxy-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()
重要注意事项
-
避免无限循环:
- 如果认证失败,服务端可能继续返回
401
或407
状态码,这个时候我们需要添加退避策略或者控制重试次数。 - 确保在
Authenticator
中检查重试次数或响应的请求历史,以避免无限重试。
kotlinval limitedRetryAuthenticator = Authenticator { _, response -> if (response.request.header("Authorization") != null) { // 防止无限重试 null } else { val credentials = Credentials.basic("username", "password") response.request.newBuilder() .header("Authorization", credentials) .build() } }
- 如果认证失败,服务端可能继续返回
-
线程安全性:
- 如果
Authenticator
需要访问共享资源(如刷新令牌),确保实现是线程安全的。
- 如果
-
避免将敏感信息硬编码:
- 使用安全存储(如 Android 的
Keystore
)来存储凭据。
- 使用安全存储(如 Android 的