Java 无法使基本http身份验证在Jersey中工作

Java 无法使基本http身份验证在Jersey中工作,java,rest,ssl,jersey,jersey-client,Java,Rest,Ssl,Jersey,Jersey Client,我正在尝试使用Jersey 1.X版本连接到安全的外部rest服务 我使用了以下代码 public class MyRestClient { private static final String API_USER_NAME = "some value"; private static final String API_PASSWORD = "some value"; private static final String REST_URL = "https://<someva

我正在尝试使用Jersey 1.X版本连接到安全的外部rest服务

我使用了以下代码

public class MyRestClient
{
  private static final String API_USER_NAME = "some value";
  private static final String API_PASSWORD = "some value";
  private static final String REST_URL = "https://<somevalue>";

  public static void main(String[] args)
  {
    ClientConfig config = new DefaultClientConfig();
    Client client = Client.create(config);
    client.addFilter(new HTTPBasicAuthFilter(API_USER_NAME, API_PASSWORD));
    WebResource webResource =
      client.resource(UriBuilder.fromUri(REST_URL).build());

    ClientResponse response = webResource.post(ClientResponse.class);
    System.out.println(response);
  }
}
我检查了这个外部rest服务的API,它说它支持基本的HTTP身份验证,但我不知道为什么我一直遇到这个错误


有什么想法吗?

因为基本身份验证本身缺乏安全性,所以通常是通过SSL完成的,正如您在URL中的
https
模式中看到的那样。有了SSL,就可以使用。SSL握手包括服务器发送其证书和客户端检查其信任库以查看证书是否可信。平台应具有其信任的证书颁发机构列表。例如,如果我们尝试访问

WebTarget target = client.target("https://wikipedia.org");
这将在维基百科发送的证书由系统中的可信机构签名时起作用。另一方面,如果来自服务器的证书没有由其中一个集群授权机构签名,那么SSL握手将失败

如果是这种情况,则需要配置
Client
来处理SSL握手,这就是为什么会出现异常。关于如何配置
客户端
以使用
https


更新
你提供的链接已经失效,所以我不知道什么是“myTrustManager”和“hostnameVerifier”…你能分享一些我如何提供的信息吗

步骤2: 我们需要在应用程序中设置基本身份验证。这可以在web.xml中完成。打开项目的web.xml并将其添加到

步骤4: 现在我们可以测试它了。如果您已经在Netbeans上安装了Tomcat,那么我们需要做的就是运行并选择服务器。这将自动打开浏览器到我们的
index.jsp
。该文件不安全,因为它不符合out安全约束的
/webapi/*
。单击Jersey资源链接,您将看到基本的身份验证登录。分别为用户名和密码键入
peeskillet
secret
。现在您可以访问资源了

步骤5: 以上所有这些只是为我们设置了基本身份验证,但是因为所有基本身份验证都是,只是base64编码我们的用户名和密码,它可以很容易地被解码,所以我们需要通过安全连接进行身份验证

我们需要做的第一件事是为服务器创建密钥库。我们将在这里创建一个自签名证书,这只应该在开发中完成。在生产环境中,您将希望从受信任的CA机构获得证书

cd
/conf
并键入以下内容(全部在一行上)

您现在应该在
conf
dir中看到一个文件
tomcat keystore.jks
。现在我们可以导出证书了

keytool -export -alias localhost -rfc -keystore ./tomcat-keystore.jks > ./tomcat.cert
系统将提示您输入密码,键入
supersecret
。您现在应该看到在
conf
dir中创建的
tomcat.cert
文件。将该文件复制到上面创建的应用程序的项目根目录中

从命令行
cd
到项目根目录,输入
tomcat.cert
的位置,然后键入以下内容

keytool -import -alias tomcatCert -file ./tomcat.cert -keystore ./client-truststore.jks
系统将提示您输入信任库的密码。使用
trustpass
。您需要输入两次。完成后,它将提示信任证书,键入
yes
并输入。现在,您应该在项目根目录中看到一个
client-truststore.jks
文件。这就是我们将用于客户端应用程序的内容

现在我们只需要配置Tomcat以使用连接的密钥库。在
/conf/server.xml
中,在
元素内 . (注意Tomcat 7可能有点不同)

你应该能够运行这个,它应该打印出来
明白了。我们完了

因为这个问题是关于Jersey 1的,所以我只想提一下,您可以轻松创建Jersey 1应用程序。从第一步开始,只需使用Maven原型的坐标

  • groupId:com.sun.jersey.archetypes
  • artifactId:jersey quickstart webapp
  • 版本:1.18.1
在Netbeans中,只需按照上述步骤操作,但选择
com.sun.jersey.archetypes
版本的
jersey快速启动webapp

对于Jersey 1,您可以使用原始答案中的代码,只需添加基本的身份验证过滤器,就像OP在原始帖子中所做的那样,设置用户名和密码,当然还可以更改url

如果帖子中有任何错误,请告诉我。我还没有机会校对:-)

一些资源

这不是身份验证的问题,而是验证SSL证书的问题。服务器使用的证书是如何签名的?Java是否知道CA?您提供的链接的可能副本已死亡,因此我不知道“myTrustManager”和“hostnameVerifier”是什么…您能否分享一些关于如何提供该链接的信息?谢谢@peeskillet。我没有安全证书方面的经验,但如果您允许的话,我想问您更多。谢谢@peeskillet。我没有安全证书方面的经验,但如果您允许的话,我想问您更多的问题。目前我在独立模式(main方法)下运行我的应用程序,如果我在web应用程序中运行代码,那么我就不需要再做任何证书导入了,因为我已经做过了?假设我使用不同的jdk转移到一个新的开发环境中,那么我需要再次执行证书导入正确吗?您的意思是希望在webapp中使用相同的客户端代码吗?如果是的话,你会没事的。您可以使用相同的信任库。只要证书不变,您就可以继续使用它。在SSL握手期间,服务器发送相同的证书。SSL引擎将使用您所创建的证书验证证书
mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
    -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
    -DgroupId=com.example -DartifactId=secured-rest-app -Dpackage=secured.rest.app \
    -DarchetypeVersion=2.13 
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Secured Rest App</web-resource-name>
        <url-pattern>/webapi/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
</security-constraint>

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>secured-rest-app.com</realm-name>
</login-config>

<security-role>
    <role-name>user</role-name>
</security-role>
<user password="secret" roles="user" username="peeskillet"/>
keytool -genkey -alias localhost -keyalg RSA -keysize 1024
        -dname "CN=localhost"
        -keypass supersecret
        -keystore tomcat-keystore.jks
        -storepass supersecret
keytool -export -alias localhost -rfc -keystore ./tomcat-keystore.jks > ./tomcat.cert
keytool -import -alias tomcatCert -file ./tomcat.cert -keystore ./client-truststore.jks
<Connector port="8443" 
    protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="150" 
    SSLEnabled="true" 
    scheme="https" 
    secure="true"
    keystoreFile="absolute/path/to/tomcat-keystore.jks"
    keystorePass="supersecret"
    clientAuth="false" 
    sslProtocol="TLS" />
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Secured Rest App</web-resource-name>
        <url-pattern>/webapi/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

public class SimpleClientApp {

    private static final String TRUSTSTORE_FILE = "client-truststore.jks";
    private static final String TRUSTSTORE_PASSWORD = "trustpass";
    private static final String APP_URL 
            = "https://localhost:8443/secured-rest-app/webapi/myresource";

    public static void main(String[] args) throws Exception {
        KeyStore truststore = KeyStore.getInstance("JKS");
        truststore.load(new FileInputStream(TRUSTSTORE_FILE), 
                                            TRUSTSTORE_PASSWORD.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(truststore);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        Client client = ClientBuilder.newBuilder()
                .sslContext(sslContext).build();
        client.register(HttpAuthenticationFeature.basic("peeskillet", "secret"));

        Response response = client.target(APP_URL).request().get();
        System.out.println(response.readEntity(String.class));

    }
}