由于基本身份验证本身缺乏安全性,因此通常通过 SSL 完成,您可以在 URL 中的 https 架构中看到。使用 SSL,使用了 certificates。 SSL 握手包括服务器发送其证书和客户端检查其信任库以查看证书是否可信。该平台应该有一个它信任的证书颁发机构列表。例如,如果我们尝试访问
WebTarget target = client.target("https://wikipedia.org");
这将起作用,因为维基百科发送的证书由系统中的受信任机构签名。另一方面,如果来自服务器的证书未由这些受信任的权威机构之一签名,则 SSL 握手将失败。
如果是这种情况,则需要将 Client 配置为处理 SSL 握手,这就是您收到异常的原因。您可以在here 看到一些关于如何配置Client 以使用https 的好答案
更新
您提供的链接已失效,所以我不知道 'myTrustManager' 和 'hostnameVerifier' 是什么...您能否分享一些有关如何提供该链接的信息?
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.junit.Test;
public class JUnitTest {
private static final String TRUSTSTORE_FILE = "<location-of-truststore";
private static final String TRUSTSTORE_PASSWORD = "trustStorePassword";
@Test
public void test() 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("SSL");
sslContext.init(null, tmf.getTrustManagers(), null);
ClientConfig config = new DefaultClientConfig();
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
new HTTPSProperties(null, sslContext));
Client client = Client.create(config);
final String httpsUrl = "https://...";
ClientResponse response = client.resource(httpsUrl).get(ClientResponse.class);
System.out.println(response.getStatus());
System.out.println(response.getEntity(String.class));
}
}
基本上,您需要从拥有 API 的人那里获得X.509 Certificate(有关编程方式,请参见下面的链接)。然后将其导入您的信任库。这就是您的客户知道信任连接的方式。如果您相信服务器就是他们所说的那个人,那么连接可以被加密。
获得证书后,您可以使用Java keytool 将其导入。通过这样做
keytool -import -alias serverCert -file <cert.file> -keystore <client_trust_file>
您将被要求输入密码。然后问你是否信任证书。输入“是”,然后你就完成了。这是您输入的文件 (client_trust_file) 和密码,应该在上面的代码中使用。
更新 2
有关创建通过与 Tomcat 的安全 SSL 连接的简单应用程序的说明。使用上面的客户端代码来访问它。我将使用 Netbeans 8,但也会尝试以一般方式包含执行此操作的说明。我还将使用 Tomcat 8(配置可能与 Tomcat 7 略有不同。您应该查阅文档以了解任何差异)。我将使用 Maven,所以希望您使用起来很舒服。
第 1 步:
创建一个新应用。我将从 Maven 原型创建一个简单的 Jersey 应用程序。在 Netbeans 中
文件→新建项目→Maven→来自Archetype的项目→搜索“jersey-quickstart-webapp”;选择groupId为“org.glassfish.jersey.archetypes”的那个→下一步→将项目命名为“secured-rest-app”→希望你能完成剩下的。你应该最终得到一个 Maven 应用程序。
在任何其他支持 Maven 的 IDE 中,只需查找带有坐标的原型:
- groupId:org.glassfish.jersey.archetypes
- artifactId: jersey-quickstart-webapp
- 版本:2.13
从命令行:执行
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
第 2 步:
我们需要在应用程序中设置基本身份验证。这可以在 web.xml 中完成。打开项目的 web.xml 并将其添加到 </servlet-mapping> 下方
<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>
第三步:
现在我们只需要在 Tomcat 中设置领域。默认情况下,Tomcat 使用域名UserDatabaseRealm。它基本上只是从 xml 文件中读取。这可能不是生产中最理想的方式,但这是最容易使用的示例。有关领域的更多信息,请参阅Realm Configuration HOW-TO。对于这个特定领域,文件已经设置好了。我们只需要添加我们的用户。打开<tomcat-home>/conf/tomcat-users.xml,在<tomcat-users>里面输入如下用户
<user password="secret" roles="user" username="peeskillet"/>
第四步:
现在我们可以测试它了。如果您已经在 Netbeans 上安装了 Tomcat,我们需要做的就是Run 并选择服务器。这应该会自动打开浏览器到我们的index.jsp。该文件不受保护,因为它不符合<url-pattern>/webapi/*</url-pattern> of out 安全约束。单击 Jersey Resource 链接,您将看到 Basic Auth 登录。分别输入peeskillet 和secret 作为用户名和密码。现在您可以访问该资源了。
第五步:
以上所有内容只是为我们设置了基本身份验证,但由于所有基本身份验证都只是对我们的用户名和密码进行 base64 编码,因此可以轻松解码,因此我们需要通过安全连接进行身份验证。
我们需要做的第一件事是为我们的服务器创建一个密钥库。我们将在这里创建一个自签名证书,这应该只在开发中完成。在生产中,您需要从受信任的 CA 机构获得证书
cd 到 <tomcat-home>/conf 并输入以下内容(全部在一行上)
keytool -genkey -alias localhost -keyalg RSA -keysize 1024
-dname "CN=localhost"
-keypass supersecret
-keystore tomcat-keystore.jks
-storepass supersecret
您现在应该在conf 目录中看到一个文件tomcat-keystore.jks。现在我们可以导出证书了。
keytool -export -alias localhost -rfc -keystore ./tomcat-keystore.jks > ./tomcat.cert
系统将提示您输入密码,输入supersecret。您现在应该看到在 conf 目录中创建的 tomcat.cert 文件。将该文件复制到您在上面创建的应用程序的项目根目录中。
从命令行cd到项目根目录,找到tomcat.cert的位置并输入以下内容
keytool -import -alias tomcatCert -file ./tomcat.cert -keystore ./client-truststore.jks
系统将提示您输入信任库的密码。使用trustpass。您将需要输入两次。完成后会提示信任证书,输入yes回车。您现在应该在项目根目录中看到一个client-truststore.jks 文件。这就是我们将用于我们的客户端应用程序的内容。
现在我们只需要配置 Tomcat 以使用我们的密钥库进行连接。在<tomcat-home>/conf/server.xml 中,在<Service> 元素内
. (注意 Tomcat 7 可能有点不同)
<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" />
最后,在我们的 web 应用中,我们应该通过更改 <security-constraint> 来添加安全连接支持
<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>
现在我们可以使用我们的客户端代码了。
第 6 步:
上面的代码使用 Jersey 1 客户端。我们使用的是 Jersey 2,所以代码会略有不同。在应用程序的任何地方,只需创建一个带有main 方法的类来运行我们的客户端。这是我使用的:
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));
}
}
你应该能够运行它并且它应该打印出Got it!。我们完成了!
由于这个特定问题是关于 Jersey 1 的,所以我只想提一下,您可以轻松地创建 Jersey 1 应用程序。从第一步开始,只需使用 Maven 原型的坐标
- groupId:com.sun.jersey.archetypes
- artifactId: jersey-quickstart-webapp
- 版本:1.18.1
在 Netbeans 中,只需按照上述步骤操作,但选择 com.sun.jersey.archetypes 版本的 jersey-quickstart-webapp。
使用 Jersey 1,您可以使用原始答案中的代码,只需添加 Basic Auth 过滤器,就像 OP 在原始帖子中所做的那样,设置用户名和密码并更改 url。
如果帖子中有任何错误,请告诉我。我还没有机会校对这个:-)
一些资源