Java 使用 HTTP Commons 客户端的基本身份验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19679320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 19:20:37  来源:igfitidea点击:

Basic Authentication using HTTP Commons Client

javaapache-commons-httpclient

提问by The_Lost_Avatar

I am looking at this link an am trying to send requests to the server

我正在查看此链接并尝试向服务器发送请求

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html

public class Test {
    public static void main(String[] args) throws ClientProtocolException, IOException {

        DefaultHttpClient httpClient;
        URL url = new URL("https://9.5.127.34:443");
        httpClient = getSSLHttpClient(url);
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope("https://9.5.127.34", AuthScope.ANY_PORT),
                new UsernamePasswordCredentials("root", "passw0rd"));


         httpClient.setCredentialsProvider(credsProvider);


        HttpGet httpget = new HttpGet("https://9.5.127.34/powervc/openstack/volume/v1/115e4ad38aef463e8f99991baad1f809//volumes/3627400b-cd98-46c7-a7e2-ebce587a0b05/restricted_metadata");
        HttpResponse response = httpClient.execute(httpget);
        BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        String line = "";
        while ((line = rd.readLine()) != null) {

            System.out.println(line);

            }   
        }

But it is giving me error as

但它给了我错误

Authentication required

Please tell me what I am doing wrongly. Thanx in Advance

请告诉我我做错了什么。提前致谢

采纳答案by Roman Vottner

Maybe you should try to send the authentication parameters preemptively like explained here: http://hc.apache.org/httpclient-legacy/authentication.html- but I'm not sure if this relates to your version.

也许您应该尝试像这里解释的那样抢先发送身份验证参数:http: //hc.apache.org/httpclient-legacy/authentication.html- 但我不确定这是否与您的版本有关。

Mat Mannion (@MatMannion) described probably a more common method, which should work with the current version: Preemptive Basic authentication with Apache HttpClient 4

Mat Mannion (@MatMannion) 描述了可能更常见的方法,它应该适用于当前版本:Preemptive Basic authentication with Apache HttpClient 4

Basically you just need to add a HTTP-header field containing the key: "authorization" and a base64 encoded string of the username and the password (combined together and then base64 encoded) or the way @Jonathan or @AdamBatkin presented it in the same thread (linked above)

基本上,您只需要添加一个包含密钥的 HTTP 标头字段:“授权”和用户名和密码的 base64 编码字符串(组合在一起,然后进行 base64 编码)或 @Jonathan 或 @AdamBatkin 以相同的方式呈现它的方式线程(上面链接)



@edit:

@编辑:

After having had a bit of spare-time I took your example code and throw it into Netbeans (yeah, I want to get a bit more familiar with NB) and built a simple jetty server demo which uses SSL and basic auth and an Apache HttpClient to invoke a simple hello world servlet to showcase how the client needs to define SSL and basic auth. Note further that some of the code was taken from the official docs and the keystore as well as the truststore are setup like explained here.

在有一点空闲时间后,我把你的示例代码扔进了 Netbeans(是的,我想更熟悉 NB)并构建了一个简单的码头服务器演示,它使用 SSL 和基本身份验证以及一个 Apache HttpClient调用一个简单的 hello world servlet 来展示客户端需要如何定义 SSL 和基本身份验证。此外,值得注意的是一些代码是从官方文档拍摄和密钥库以及与信任是建立像解释这里

Below please find the complete code (except the keystores which are binary) of the project (maybe someone other might find it useful too).

请在下面找到项目的完整代码(除了二进制的密钥库)(也许其他人也可能觉得它很有用)。

pom.xml

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>at.rovo.test</groupId>
  <artifactId>HttpClientExample</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>HttpClientExample</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <!-- Client -->
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.3</version>
      <type>jar</type>
    </dependency>
    <!-- Server -->
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
      <version>9.1.0.M0</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-security</artifactId>
      <version>9.1.0.M0</version>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-servlet</artifactId>
      <version>9.1.0.M0</version>
      <type>jar</type>
    </dependency>
  </dependencies>
</project>

JettyServer.java

JettyServer.java

package at.rovo.test.httpclient;

import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.security.Constraint;

public class JettyServer 
{
    private String REALM;

    public static void main( String[] args ) throws Exception
    {
        new JettyServer();
    }

    public JettyServer() throws Exception
    {
        Server server = new Server(8080);
        server.addConnector(this.getSslChannelConnector(server));
        server.setStopAtShutdown(true);

        // create the context handler for the server        
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        context.setClassLoader(Thread.currentThread().getContextClassLoader());
        // attach the security handler to it that has basic authentication
        context.setSecurityHandler(this.getSecurityHandler());

        server.setHandler(context);
        // define the processing servlet
        context.addServlet(new ServletHolder(new ProcessingServlet()), "/process");

        server.start();
        server.join();
    }

    private Connector getSslChannelConnector(Server server)
    {
        try
        {           
            String keyStore = this.getClass().getResource("/serverKey.jks").toURI().getPath();

            SslConnectionFactory sslConnFactory = new SslConnectionFactory();
            sslConnFactory.getSslContextFactory().setKeyStorePath(keyStore);
            sslConnFactory.getSslContextFactory().setKeyStorePassword("keystorePW");
            sslConnFactory.getSslContextFactory().setKeyManagerPassword("jettyPW");

            HttpConfiguration config = new HttpConfiguration();
            ConnectionFactory connFactory = new HttpConnectionFactory(config);

            ServerConnector connector = new ServerConnector(server, sslConnFactory, connFactory);
            connector.setPort(8443);
            connector.setHost("localhost");
            connector.setIdleTimeout(30000);
            return connector;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    private SecurityHandler getSecurityHandler() throws Exception 
    {
        // add authentication
        Constraint constraint = new Constraint(Constraint.__BASIC_AUTH,"user");
        constraint.setAuthenticate(true);
        constraint.setRoles(new String[]{"user","admin"});

        // map the security constraint to the root path.
        ConstraintMapping cm = new ConstraintMapping();
        cm.setConstraint(constraint);
        cm.setPathSpec("/*");

        // create the security handler, set the authentication to Basic
        // and assign the realm.
        ConstraintSecurityHandler csh = new ConstraintSecurityHandler();
        csh.setAuthenticator(new BasicAuthenticator());
        csh.setRealmName(REALM);
        csh.addConstraintMapping(cm);

        // set the login service
        csh.setLoginService(getHashLoginService());

        return csh;
    }

    private HashLoginService getHashLoginService() throws Exception 
    {
        // load the authentication data from a simple property file
        HashLoginService hls = new HashLoginService();
        hls.setName(REALM);
        hls.setConfig(this.getClass().getResource("/realm.properties").toURI().toString());
        hls.setRefreshInterval(0);
        return hls;
    }
}

ProcessingServlet.java

处理Servlet.java

package at.rovo.test.httpclient;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ProcessingServlet extends HttpServlet
{
    public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException 
    {
        response.setContentType("text/html");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().println("<h1>Hello World</h1>");
        response.getWriter().println("session=" + request.getSession(true).getId());
  }
}

realm.properties

领域.properties

admin: admin123, admin
root: passw0rd, user

Client.java

客户端.java

package at.rovo.test.httpclient;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class Client 
{
    public static void main(String[] args) throws Exception 
    {
        CloseableHttpClient httpClient;

        // SSL setup
        KeyStore trustStore  = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream instream = new FileInputStream(new File(Client.class.getResource("/clientTrust.jks").toURI()));
        try 
        {
            trustStore.load(instream, "truststorePW".toCharArray());
        } 
        finally 
        {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom()
                .loadTrustMaterial(trustStore)
                .build();
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);


        HttpHost targetHost = new HttpHost("localhost", 8443, "https");

        // Basic Auth setup
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(
                new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                new UsernamePasswordCredentials("root", "passw0rd"));
        httpClient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .setDefaultCredentialsProvider(credsProvider)
                .build();

        try
        {
            HttpGet httpget = new HttpGet("https://localhost:8443/process");

            System.out.println("executing request: " + httpget.getRequestLine());
            System.out.println("to target: " + targetHost);

            CloseableHttpResponse response = httpClient.execute(httpget);
            try
            {
                HttpEntity entity = response.getEntity();

                System.out.println("--------------------------------------------------");
                System.out.println(response.getStatusLine());
                if (entity != null)
                {
                    System.out.println("Response content length: "+entity.getContentLength());
                }
                BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                String line;
                while ((line = rd.readLine()) != null) 
                {
                    System.out.println(line);
                }
                EntityUtils.consume(entity);
            }
            finally
            {
                response.close();
            }
        }
        finally
        {
            httpClient.close();
        }
    }
}

Bear with me as I'm hardly checking for errors, but this is a quick&dirty example to demonstrate just the functionality of an SSL-secured Apache HttpClient that uses basic authentication.

请耐心等待,因为我几乎不检查错误,但这是一个快速而肮脏的示例,仅用于演示使用基本身份验证的 SSL 保护的 Apache HttpClient 的功能。