我刚刚浏览了所有 Spring 5 文档,但没有找到与 WebClient 支持开箱即用的基于摘要的身份验证相关的任何内容。是否有任何解决方法可以使用 webClient 并仍然调用基于摘要的安全 API?
不,目前没有这样的支持。
您可以考虑通过实施
org.springframework.web.reactive.function.client.ExchangeFunction
来实施您自己的客户支持。
或者(因为滚动您自己的支持可能很困难),您可以在 Spring Security 项目上创建一个新问题,并看到社区对此类功能感兴趣。
所以这已经很晚了,但我在尝试将我的反应式 Spring Boot 应用程序和 WebClient 与 Atlas API 集成时遇到了同样的问题。
下面的要点为我解决了这个问题。我必须下载 git repo (https://github.com/vzhn/netty-http-authenticator) 并自己构建它,因为发布 1.5 的 Maven 工件不足以让要点工作,但是当完成后,可以使摘要身份验证与 WebClient 一起使用。
https://gist.github.com/sebphil/e3773a87e5bf197193deec5c9512bd2d
下面给出了与 webClient 一起使用基于摘要的身份验证的临时解决方案,直到 Spring 社区修复此问题。
public Mono<String> getDigestCallByUserId(String userId) {
String url = serviceUrl + uri;
return webClient.get()
.uri(url)
.exchange()
.flatMap(resp -> {
if (resp.statusCode().equals(HttpStatus.UNAUTHORIZED)) {
return getSectionsByUserId(userId, resp.headers().header(Constants.HEADER_AUTHENTICATE).get(0), url, uri);
} else {
return resp.bodyToMono(String.class);
}
});
}
public Mono<String> getDigestCallByUserId(String userId, String digestAuthResponse, String url, String uri) {
return webClient.get()
.uri(url)
.header(Constants.HEADER_AUTHORIZATION, getDigestAuthHeader(digestAuthResponse, username, password, uri, HttpMethod.GET.toString()))
.retrieve()
.bodyToMono(String.class)
.log(LOGGER.getName(), Level.SEVERE, SignalType.ON_ERROR, SignalType.CANCEL);
}
/**
* @param values
* @returns the appended string for the given list of strings
*/
public static String getStringsAppended(String... values) {
StringBuilder sb = new StringBuilder();
for (String s : values) {
sb.append(s);
}
return sb.toString();
}
/**
* @param digestChallenge
* @param username
* @param password
* @param uri
* @param httpMethod
* @returns the Digest based authorization header
*/
public static String getDigestAuthHeader(String digestChallenge, String username, String password, String uri,
String httpMethod) {
Pattern digestChallengePattern = Pattern.compile(Constants.PATTERN_DIGEST_CHALLENGE);
Matcher m = digestChallengePattern.matcher(digestChallenge);
if (m.matches()) {
String realm = m.group(Constants.DIGEST_AUTH_REALM);
String qop = m.group(Constants.DIGEST_AUTH_QOP);
String nonce = m.group(Constants.DIGEST_AUTH_NONCE);
String clientNonce = DigestScheme.createCnonce();
String nonceCount = String.format("%08x", 1);
String ha1 = hash(getStringsAppended(username, Constants.COLON, realm, Constants.COLON, password));
String ha2 = hash(getStringsAppended(httpMethod, Constants.COLON, uri));
String response = hash(getStringsAppended(ha1, Constants.COLON, nonce, Constants.COLON, nonceCount,
Constants.COLON, clientNonce, Constants.COLON, qop, Constants.COLON, ha2));
return getStringsAppended(Constants.DIGEST, StringUtils.SPACE, Constants.DIGEST_AUTH_USERNAME,
Constants.EQUAL, Constants.DOUBLE_QUOTE, username, Constants.DOUBLE_QUOTE, Constants.COMMA,
Constants.DIGEST_AUTH_REALM, Constants.EQUAL, Constants.DOUBLE_QUOTE, realm, Constants.DOUBLE_QUOTE,
Constants.COMMA, Constants.DIGEST_AUTH_NONCE, Constants.EQUAL, Constants.DOUBLE_QUOTE, nonce,
Constants.DOUBLE_QUOTE, Constants.COMMA, Constants.DIGEST_AUTH_URI, Constants.EQUAL,
Constants.DOUBLE_QUOTE, uri, Constants.DOUBLE_QUOTE, Constants.COMMA,
Constants.DIGEST_AUTH_RESPONSE, Constants.EQUAL, Constants.DOUBLE_QUOTE, response,
Constants.DOUBLE_QUOTE, Constants.COMMA, Constants.DIGEST_AUTH_QOP, Constants.EQUAL,
Constants.DOUBLE_QUOTE, qop, Constants.DOUBLE_QUOTE, Constants.COMMA, Constants.DIGEST_AUTH_NC,
Constants.EQUAL, Constants.DOUBLE_QUOTE, nonceCount, Constants.DOUBLE_QUOTE, Constants.COMMA,
Constants.DIGEST_AUTH_CNONCE, Constants.EQUAL, Constants.DOUBLE_QUOTE, clientNonce,
Constants.DOUBLE_QUOTE);
}
return StringUtils.EMPTY;
}