最近遇到一个需求,需要打开一个受Digest Auth 保护的Api接口,然后保持长连接,不断接收流里面的数据。
网上查阅相关资料后,使用现有框架,可以做到使用Digest Auth授权访问,但是做不到不断读取长连接推送的数据。而使用HttpURLConnection 可以做到不断读取长连接推送的数据,但没有现成的资料可以直接做到Digest Auth ,所以只能自己计算相关的校验数据和编写校验方法。
特此发下下相关的代码作为记录,也希望可以帮到其他有需要的人
public class Sample {
public static void main(String[] args) throws IOException {
String requestMethod = "<RequestMethod>";
String username = "<username>";
String password = "<password>";
String requestUri = "<Request uri : sample /api/login >";
URL authRequest = new URL("<Request url>");
HttpURLConnection conn = (HttpURLConnection) authRequest.openConnection();
conn.setRequestMethod(requestMethod);
//直接调用一次让接口生成摘要认证需要使用的认证信息
String wwwAuthenticate = conn.getHeaderField("WWW-Authenticate");
String[] wwwAuthenticateTemp = wwwAuthenticate.split(",");
Map<String, String> wwwAuthenticateMap = new HashMap<>();
for (String s : wwwAuthenticateTemp) {
String[] temp = s.split("=");
wwwAuthenticateMap.put(temp[0].trim().replace("\"", ""), temp[1].trim().replace("\"", ""));
}
String qop = wwwAuthenticateMap.get("qop");
String digestRealm = wwwAuthenticateMap.get("Digest realm");
String nonce = wwwAuthenticateMap.get("nonce");
String algorithm = wwwAuthenticateMap.get("algorithm");
String clientNonce = UUID.randomUUID().toString().replace("-", "");
String ha1 = DigestUtils.md5Hex(username + ":" + digestRealm + ":" + password);
/*
* 如果 qop 值为auth或未指定,ha2 = MD5(method : digestURI)
* 如果 qop 值为auth-int,ha2 = MD5(method : digestURI :MD5(entityBody))
*
* 如果 qop 值为auth或auth-int,那么 response = MD5(ha1 : nonce : nonceCount : clientNonce : qop :ha2)
* 如果 qop 末指定,那么 response = MD5(HA1 :nonce : HA2)
*
* 我所测试的接口qop为auth,并未能测试其他情況,所以下面就以qop=auth來开发测试
*/
String ha2 = DigestUtils.md5Hex(requestMethod + ":" + requestUri);
String response = DigestUtils.md5Hex(ha1 + ":" + nonce + ":00000001:" + clientNonce + ":" + qop + ":" + ha2);
String authorization = "Digest username=\"" + username + "\", realm=\"" + digestRealm
+ "\", nonce=\"" + nonce + "\", uri=\"" + requestUri + "\", algorithm=\"" + algorithm + "\""
+ ", qop=" + qop + ",nc=00000001, cnonce=\"" + clientNonce + "\", response=\"" + response + "\", opaque=\"";
/*
* 计算好验证过数据后,使用这验证数据重新调用接口
*/
URL request = new URL("<Request url>");
HttpURLConnection conn2 = (HttpURLConnection) request.openConnection();
conn2.setRequestMethod(requestMethod);
conn2.setRequestProperty("Authorization", authorization);
InputStream inputStream;
if (conn2.getResponseCode() == 200) {
/*
* 假如你需要使用到长连接,在这里动一下手脚就行
* 写个while循环,不断读取流里面的内容
*/
inputStream = conn2.getInputStream();
} else {
inputStream = conn2.getErrorStream();
}
byte[] b = new byte[inputStream.available()];
inputStream.read(b);
System.out.println(new String(b));
}
}
需要导入一个包,用于MD5摘要
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>