使用Nginx代理restful實現SSL鏈路加密

1 目標說明

1.1 調研目的

本次調研主要爲了解決兩個問題:java

  • 不須要對restful的web容器作任何配置,實現對restful鏈路進行加密;
  • 方便restful應用進行擴展,採用多個服務進行負載均衡,以提高吞吐量。

1.2 目標網絡模型

    但願達到的目標網絡模型以下:nginx

1.3 SSL說明

    經過對SSL的學習,結合自身業務的考慮,對SSL的使用作以下說明:git

    我這裏SSL使用TLSv1,而且服務端不須要校驗客戶端的身份合法性,則使用SSL單向認證方式,只須要服務端證書。另外咱們只須要用到SSL的鏈路加密,因此能夠設置客戶端對服務端證書保持永久信任web

2 調研過程

這裏restful使用jersey來實現,使用jetty做爲javaee容器。windows

2.1 測試非加密restful

經過jetty發佈非加密restful服務,url爲 http://localhost:8080/api/v1/....api

2.1.1 服務端代碼

web.xmlrestful

<servlet>
        <servlet-name>RestApplication</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.spiro.test.jersey.MyApplication</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>RestApplication</servlet-name>
        <url-pattern>/api/v1/*</url-pattern>
    </servlet-mapping>

Resource:網絡

import com.spiro.test.jersey.entity.Terminal;

import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.List;

@Path("terminals")
@Singleton
public class TerminalsResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAll() {

        List<Terminal> terminals = new ArrayList<Terminal>();

        Terminal ter1 = new Terminal();
        ter1.setId("101");
        ter1.setDesc("I'm 101");
        terminals.add(ter1);

        Terminal ter2 = new Terminal();
        ter2.setId("102");
        ter2.setDesc("I'm 102");
        terminals.add(ter2);


//        if(true) {
//            return Response.status(Response.Status.UNAUTHORIZED).build();
//        }

        return Response.ok(terminals).build();
    }
}

ResourceConfig:session

import com.spiro.test.jersey.resources.TerminalsResource;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        register(TerminalsResource.class);
        register(JacksonFeature.class);
    }
}

2.1.2 客戶端代碼

public static void testHttp() {

        ClientConfig clientConfig = new ClientConfig();
        Client client = ClientBuilder.newClient(clientConfig);

        String url = "http://localhost:8080/api/v1/";

        String entity = client.target(url)
                .path("terminals")
                .request(MediaType.APPLICATION_JSON)
                .get(String.class);

        System.out.println(entity);
    }

經測試成功打印:[{"id":"101","desc":"I'm 101"},{"id":"102","desc":"I'm 102"}]app

2.2 測試https 加密restful

2.2.1 nginx安裝配置

    在windows7機器上安裝nginx-1.10.1,配置以下:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    server {
        listen       443 ssl;
        server_name  localhost;

		ssl_certificate       D:/server.crt;
		ssl_certificate_key   D:/_server.key;

        location / {
            proxy_pass   http://127.0.0.1:8080;
        }
    }
}

2.2.2 服務端代碼

   同2.1.1

2.2.3 客戶端代碼

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
    public void checkClientTrusted(X509Certificate[] certs, String authType) {
    }
    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }
}
};

// Install the all-trusting trust manager
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();

String entity = client.target("https://127.0.0.1:443/api/v1/")
        .path("terminals")
        .request(MediaType.APPLICATION_JSON)
        .get(String.class);

System.out.println(entity);

設置客戶端請求鏈接爲ssl加密,而且客戶端永久信任服務端,不對服務端證書進行驗證。

經測試成功打印:[{"id":"101","desc":"I'm 101"},{"id":"102","desc":"I'm 102"}]

3 總結

    經測試,能夠經過nginx https代理restful 實現鏈路加密,後續可經過nginx upstream實現負載均衡。

完整代碼請查看

相關文章
相關標籤/搜索