【问题标题】:Basic Authentication with RestTemplate (3.1)使用 RestTemplate (3.1) 进行基本身份验证
【发布时间】:2013-01-01 05:42:12
【问题描述】:

我正在尝试使用 Java 重现以下 curl 命令:

curl -v -u user:pass http://myapp.com/api

此命令返回一些 JSON 数据。

我的错误Java实现如下:

@Test
public void callTest() {
    RestTemplate restTemplate = createRestTemplate("user", "pass");
    URI uri = new URI("http://myapp.com/api");
    String res = restTemplate.getForObject(uri, String.class);
}

private static RestTemplate createRestTemplate(String username, String password) {

    UsernamePasswordCredentials cred = new UsernamePasswordCredentials(username, password);
    BasicCredentialsProvider cp = new BasicCredentialsProvider();
    cp.setCredentials(AuthScope.ANY, cred);
    DefaultHttpClient client = new DefaultHttpClient();
    client.setCredentialsProvider(cp);
    ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);

    RestTemplate restTemplate = new RestTemplate(factory);
    // set the media types properly
    return restTemplate;
}

然而,当我执行测试时,它返回一个org.springframework.web.client.HttpClientErrorException: 401 Unauthorized 异常。

登录DEBUG时,我看不到任何有关身份验证的信息...

我在设置身份验证凭据时做错了什么?

【问题讨论】:

    标签: java spring-mvc basic-authentication apache-httpclient-4.x resttemplate


    【解决方案1】:

    httpclient v4.0 不支持抢占式认证

    看这个: http://forum.springsource.org/showthread.php?123385-Preemptive-Basic-Authentication-with-RestTemplate

    在 spring Source 中找到了这个解决方案。

    它对我有用。

    看这个:RestTemplate with Basic Auth in Spring 3.1

    【讨论】:

    【解决方案2】:

    使用实例化

    HttpClient client = new HttpClient();
    

    不再存在,并且类 DefaultHttpClient 已从 4.3 版HttpComponents HttpClient 中弃用。因此,其他答案无效或已弃用。这是我的版本,我为需要基本身份验证的休息请求编写了这个类:

    import org.apache.http.auth.AuthScope;
    import org.apache.http.auth.UsernamePasswordCredentials;
    import org.apache.http.client.CredentialsProvider;
    import org.apache.http.client.HttpClient;
    import org.apache.http.impl.client.BasicCredentialsProvider;
    import org.apache.http.impl.client.HttpClients;
    import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
    import org.springframework.web.client.RestTemplate;
    
    public class RestClient extends RestTemplate {
        public RestClient(String username, String password) {
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(
                    new AuthScope(null, -1),
                    new UsernamePasswordCredentials(username, password));
            HttpClient httpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
            setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
        }
    }
    

    然后像这样使用它,例如:

    RestClient restClient = new RestClient("username", "password");
    
    String result = restClient.postForObject(...
    

    【讨论】:

    • 谢谢!这个页面上唯一一个对我有用(不使用折旧方法)的人。
    • 扩展 RestTemplate 来做到这一点是错误的方法。将其配置为执行您需要的操作(在 Spring XML 或 Java 配置中),而不是对其进行子类化。
    • 很好的例子,@TedPennings 提出了很好的观点。谢谢你们。
    • 我已经根据需要创建了一个 RestTemplate,所以我不需要像这样子类化 - 我只是使用提供的代码来设置我的凭据。干得好。
    • 我尝试将此实现发布到特定作业的 Jenkins buildWithParameters URL,但它一直失败并显示 403 表示操作无效。对 curl 使用相同的 URL、用户和密码,这没有问题。关于为什么这不起作用的任何线索?
    【解决方案3】:

    此答案基于 @kevinpeterson 的答案,但经过重写以使用更新的 Apache HTTP 客户端。

    RestTemplate createRestTemplate(String username, String password, String host, int port ) {
        return new RestTemplate(this.createSecureTransport( username, password, host, port ));
    }
    
    ClientHttpRequestFactory createSecureTransport( String username, String password, String host, int port ){
        DefaultHttpClient client = new DefaultHttpClient();
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( username, password );
        client.getCredentialsProvider().setCredentials( new AuthScope( host, port ), credentials );
        return new HttpComponentsClientHttpRequestFactory(client);
    

    【讨论】:

    • 至少使用 Spring Framework 3.2.3 和 httpclient 4.2.3,我无法让上面的代码正常工作。我用指定的 AuthScope 和 AuthScope.ANY 都试过了,但我认为它不起作用。 Makoton 的链接解释了原因并提供了更好的解决方案。
    • 不知道您遇到了什么问题,但我在 Spring Framework 3.2.4 和 httpclient 4.2.1 中成功使用了此代码。我怀疑细微的版本差异是问题所在,但谁知道呢。
    【解决方案4】:

    我做了这样的事情 - 它对我有用:

    private RestTemplate createRestTemplate(String username, String password) {
        return new RestTemplate(this.createSecureTransport(username, password));
    }
    
    protected ClientHttpRequestFactory createSecureTransport(String username, String password){
        HttpClient client = new HttpClient();
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username,password);
        client.getState().setCredentials(AuthScope.ANY, credentials);
        CommonsClientHttpRequestFactory commons = new CommonsClientHttpRequestFactory(client);
    
        return commons;
    }
    

    这里使用:Reference Code

    【讨论】:

    • 那是旧的 HTTPClient api。我使用的是 4.x,其中 CommonsClientHttpRequestFactory 不再存在。
    猜你喜欢
    • 2016-08-24
    • 2012-02-21
    • 1970-01-01
    • 2012-10-10
    • 2014-03-22
    • 1970-01-01
    • 2014-03-26
    • 2015-08-12
    • 2017-06-13
    相关资源
    最近更新 更多