使用HTTP Commons Client进行基本身份验证

时间:2013-10-30 10:09:02

标签: java apache-commons-httpclient

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

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);

            }   
        }

但它给我的错误是

Authentication required

请告诉我我做错了什么。 Thanx in Advance

1 个答案:

答案 0 :(得分:3)

也许您应该尝试先发送身份验证参数,如下所示:http://hc.apache.org/httpclient-legacy/authentication.html - 但我不确定这是否与您的版本有关。

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

基本上你只需要添加一个包含密钥的HTTP-header字段:“authorization”和用户名和密码的base64编码字符串(组合在一起然后用base64编码)或者@Jonathan或@AdamBatkin呈现它的方式在同一个帖子中(上面链接)


@edit:

在有了一些业余时间后,我把你的示例代码扔进Netbeans(是的,我想对NB更加熟悉)并构建一个简单的jetty服务器演示,它使用SSL和基本的auth和Apache HttpClient调用一个简单的hello world servlet来展示客户端如何定义SSL和基本身份验证。请进一步注意,部分代码来自官方文档,密钥库以及信任库的设置与解释here类似。

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

的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

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

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

admin: admin123, admin
root: passw0rd, user

Client.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();
        }
    }
}

请耐心等待,因为我几乎没有检查错误,但这是一个快速而简单的示例,仅演示使用基本身份验证的SSL加密Apache HttpClient的功能。