创建具有特定范围的java.net.Authenticator

时间:2019-03-06 11:29:22

标签: java http java-11 java-http-client

我正在使用JDK11 HTTP客户端库,在其中尝试创建具有特定范围的身份验证,该范围可以与主机,端口,领域或方案(BASIC,DIGEST等)相关。

我的课堂实现是:

class CredentialsProviderAuthenticator extends Authenticator {

    private final AuthScope authScope;
    private final Credentials credentials;

    private CredentialsProviderAuthenticator(AuthScope authScope, Credentials credentials) {
        this.authScope = authScope;
        this.credentials = credentials;
    }


    public static Authenticator createAuthenticator(AuthScope authScope, Credentials credentials) {
        return new CredentialsProviderAuthenticator(authScope, credentials);
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        if ( (authScope.getScheme() == null ||  authScope.getScheme().equalsIgnoreCase(getRequestingScheme()))
                && ((authScope.getHost() == null || authScope.getHost().equalsIgnoreCase(getRequestingHost())))
                && ((authScope.getRealm() == null || authScope.getRealm().equalsIgnoreCase(getRequestingPrompt())))
                && ((authScope.getPort() < 0) || authScope.getPort() == getRequestingPort())) {

            return new PasswordAuthentication(credentials.getUserPrincipal().getName(), credentials.getPassword().toCharArray());
        }

        return null;
    }

}

当返回PasswordAuthentication实例时,此实现工作正常,但是如果找不到合适的身份验证,则客户端将引发异常。

Caused by: java.io.IOException: No credentials provided
    at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:565)
    at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:119)
    at com.imperva.shcf4j.java.http.client.ClosableSyncHttpClient.execute(ClosableSyncHttpClient.java:50)
    ... 27 more
Caused by: java.io.IOException: No credentials provided
    at java.net.http/jdk.internal.net.http.AuthenticationFilter.response(AuthenticationFilter.java:303)
    at java.net.http/jdk.internal.net.http.MultiExchange.responseFilters(MultiExchange.java:181)
    at java.net.http/jdk.internal.net.http.MultiExchange.lambda$responseAsyncImpl$5(MultiExchange.java:245)
    at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
    at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:610)
    at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:649)
    at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:478)
    at java.net.http/jdk.internal.net.http.HttpClientImpl$DelegatingExecutor.execute(HttpClientImpl.java:153)
    at java.base/java.util.concurrent.CompletableFuture$UniCompletion.claim(CompletableFuture.java:568)
    at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:638)
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
    at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073)
    at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.handle(Http1Response.java:677)
    at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.handle(Http1Response.java:603)
    at java.net.http/jdk.internal.net.http.Http1Response$Receiver.accept(Http1Response.java:594)
    at java.net.http/jdk.internal.net.http.Http1Response$HeadersReader.tryAsyncReceive(Http1Response.java:650)
    at java.net.http/jdk.internal.net.http.Http1AsyncReceiver.flush(Http1AsyncReceiver.java:228)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

我正在寻找一种方法,在这种情况下,客户端将返回401 HTTP错误代码。一种想法是创建一个实例,该实例在每次调用时生成用户名和密码,但是也许存在一种更简单的方法?

1 个答案:

答案 0 :(得分:1)

恐怕目前没有更好的选择:您提供一个身份验证器,并且如果该身份验证器不提供有效的凭据,或者您不提供任何身份验证器,您将得到一个例外,并且您可以处理您自己的代码中的401响应(您可以选择在与HttpClient :: sendAsync返回的可完成future异步注册的依赖操作中实现)。例如:

client.sendAsync(...).thenApplyAsync(resp -> handle401(client, resp))...