背景:服務器接收客戶端請求,處理並驗證。並返回服務器的驗證結果。
關於digest認證的相關概念及驗證原理查看相關的說明,此處只對處理進行貼碼。
CODE:
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
@Slf4j
@Component
public class DigestDao {
@Value("${registerUserName}")
String registerUserName;
@Value("${registerPassWord}")
String registerPassWord;
@Value("${platformId}")
String platformId;
private static final String DIGEST = "Digest ";
private static final String NONCE = "nonce";
private static final String QOP = "qop";
private static final String REALM = "realm";
private static final String NC = "nc";
private static final String CNONCE = "cnonce";
private static final String RESPONSE = "response";
private static final String URI = "uri";
private static final String HEX_LOOKUP = "0123456789abcdef";
private static final String realm = "viid";
private static final String qop = "auth";
private static final Charset defaultChatSet;
private static final MessageDigest md5;
static {
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new NullPointerException("MD5");
}
defaultChatSet = StandardCharsets.ISO_8859_1;
}
/**
* HTTP Digest驗證
* @param httpServletRequest
* @param httpResponse
* @param url
* @param type
* @return
*/
public String auth(HttpServletRequest httpServletRequest, HttpServletResponse httpResponse, String url,
String type) {
String authorization = httpServletRequest.getHeader("Authorization");
log.info("authorization:{}", authorization);
if (authorization != null) {
if (authorization.startsWith(DIGEST.trim())) {
HashMap<String, String> authFields = splitAuthFields(authorization.substring(7));
String newResponse = authFields.get(RESPONSE);
String A1 = calcDigest(registerUserName, authFields.get(REALM),
registerPassWord);//A1 = MD5("usarname:realm:password");
String A2 = calcDigest(HttpMethod.POST.toString(), authFields.get(URI));//A2 = MD5("httpmethod:uri");
String oriResponse = calcDigest(A1, authFields.get(NONCE), authFields.get(NC), authFields.get(CNONCE),
authFields.get(QOP), A2); //response = MD5("A1:nonce:nc:cnonce:qop:A2");
if (oriResponse.equals(newResponse)) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYYMMddHHmmss");
httpResponse.setStatus(HttpStatus.SC_OK);
JSONObject jsonObject = new JSONObject();
jsonObject.put("RequestURL", url);
jsonObject.put("StatusString", type + " success");
jsonObject.put("StatusCode", "0");
jsonObject.put("Id", platformId);
jsonObject.put("LocalTime", simpleDateFormat.format(new Date()));
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("ResponseStatusObject", jsonObject);
log.info(type + "success:{}", jsonObject1.toJSONString());
return jsonObject1.toJSONString();
} else {
log.info(type + " failed!");
httpResponse.setStatus(HttpStatus.SC_UNAUTHORIZED);
}
} else {
log.info("返回的非摘要認證數據!");
}
} else {
httpResponse.setStatus(HttpStatus.SC_UNAUTHORIZED);
httpResponse.setHeader("WWW-Authenticate", getAuthenticate());
}
return "";
}
private String getAuthenticate(){
return "Digest " + "realm=" + realm + ",nonce=" + getNonce() + ",qop=" + qop;
}
private String getNonce(){
md5.reset();
md5.update(("test" + System.currentTimeMillis()).getBytes(defaultChatSet));
return bytesToHexString(md5.digest());
}
private String calcDigest(String first, String ... args){
StringBuilder stringBuilder = new StringBuilder(first);
for (String str : args){
stringBuilder.append(':').append(str);
}
md5.reset();
md5.update(stringBuilder.toString().getBytes());
return bytesToHexString(md5.digest());
}
private static HashMap<String, String> splitAuthFields(String authString) {
final HashMap<String, String> fields = Maps.newHashMap();
final CharMatcher trimmer = CharMatcher.anyOf("\"\t ");
final Splitter commas = Splitter.on(',').trimResults().omitEmptyStrings();
final Splitter equals = Splitter.on('=').trimResults(trimmer).limit(2);
String[] valuePair;
for (String keyPair : commas.split(authString)) {
valuePair = Iterables.toArray(equals.split(keyPair), String.class);
fields.put(valuePair[0], valuePair[1]);
}
return fields;
}
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(HEX_LOOKUP.charAt((bytes[i] & 0xF0) >> 4));
sb.append(HEX_LOOKUP.charAt((bytes[i] & 0x0F) >> 0));
}
return sb.toString();
}
}