注意OkHttp3 自带的Digest Auth 认证存在循环请求:部分请求如下所示:
private static void digestAuth(ApiRequestVo apiRequestVo,Request.Builder requestBuilder,OkHttpClient.Builder okHttpClientBuilder){
List<Map<String, Object>> authParams = apiRequestVo.getAuthParams();
Map<String,String> map = new HashMap<>();
for (Map<String, Object> authParam : authParams) {
String value = String.valueOf(authParam.get(Params.VALUE)).trim();
if (StringUtils.isNotEmpty(value)){
map.put(String.valueOf(authParam.get(Params.NAME)).trim(),value);
}
}
if (map.size() == 2){
//这里需要来两次请求
String username = map.get(Params.USERNAME);
String password = map.get(Params.PASSWORD);
okHttpClientBuilder.retryOnConnectionFailure(true)
.connectTimeout(15, TimeUnit.SECONDS)
.authenticator(new DigestAuthenticator(username,password))
.followRedirects(false);
}
}
如果这么传入会出现 Too many follow-up requests: 21这个错误。根据Digest Auth自身请求规则,第一次是客户端传过来的认证key,第二次根据key继续请求。
详细数据如下:
第一次:
第二次:
那么根据两次发送原则我们进行分解,由我们自己操控:
@Test
public void digestAuth(){
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
Request.Builder requestBuilder = new Request.Builder();
String URL = "http://127.0.0.1:8082/digestAuth/info";
requestBuilder.url(URL);
Request request = requestBuilder.build();
OkHttpClient client = okHttpClientBuilder.build();
ApiResult apiResult = null;
try {
Response response = client.newCall(request).execute();
String header = response.header("WWW-Authenticate");
System.out.println(response);
DigestScheme mDigestScheme = new DigestScheme();
UsernamePasswordCredentials mCredentials = new UsernamePasswordCredentials("admin", "admin");
mDigestScheme.processChallenge(new BasicHeader("WWW-Authenticate", response.header("WWW-Authenticate")));
org.apache.http.HttpRequest request111 = new BasicHttpRequest(
response.request().method(),
response.request().url().toString());
String authHeader;
authHeader = mDigestScheme.authenticate(mCredentials, request111).getValue();
requestBuilder.header("Authorization",authHeader);
Response response1 = client.newCall(requestBuilder.build()).execute();
System.out.println(response1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (MalformedChallengeException e) {
throw new RuntimeException(e);
} catch (AuthenticationException e) {
throw new RuntimeException(e);
}
}
自己根据第一次请求里response里的WWW-Authenticate,反写回第二次请求的Request header中,那么就可以规避循环发送问题。