使用https安全传送消息数据,服务端用分布式。

                                                                                    关于数据安全通信设计方案

背景: 

       数据通信时需要保证数据安全,除了敏感字加密,也可以使用https服务方式传送。

技术点:

    分布式 tomcat    cxf  restful服务   jdk keytool安全密钥。

架构:

 

 

实现:

1.提供数据服务 (restful  get/post)

 

AgdRestfulServiceImpl 

 

package com.agd.service.impl;


import java.io.IOException;


import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;


import com.agd.service.AgdRestfulService;
import com.alibaba.fastjson.JSONObject;


/**
 *  restful 服务 
 *  启动成功后 可用路径测试 
 *  https://localhost:8443/agdRestFul/services/restful/init/123456
 * @author kuanghongjiang
 *
 */
@Path(value = "/")
public class AgdRestfulServiceImpl implements AgdRestfulService {
    
    @Context
    private UriInfo uriInfo;
    
    @Context
    private HttpServletRequest request;
    
    @POST
    @Path("/sendData")
    @Produces(MediaType.APPLICATION_JSON)
    public String sendData() throws IOException
    {
        System.out.println("sendData::"+ request.getAttributeNames());
        return "success";
    }
    
    @GET
    @Path("/init/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public String init(@PathParam("id")String id)
    {
    JSONObject obj = new JSONObject();
    System.out.println("my first restful");
    obj.put("id", id);
    return obj.toString();
    }
}
package com.agd.service;


import java.io.IOException;


import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;


@Path(value = "/AgdRestfulService")
public interface AgdRestfulService {
    
    @POST
    @Path("/sendData")
    @Produces(MediaType.APPLICATION_JSON)
    public String sendData() throws IOException;
    
    
    @GET
    @Path("/init/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public String init(@PathParam("id")String id);
    
}
<s<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/aop 
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd  
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd ">

<!--  为cxf 的配置 -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<bean id="agdRestfulService" class="com.agd.service.impl.AgdRestfulServiceImpl" />
<!-- 这里的地址很重要,客户端需要通过这个地址来访问WebService -->
<!-- 访问地址为   http://localhost:8080/zzMyRestFul/services/restful/  方法类path -->
<jaxrs:server id="restServiceContainer" address="/restful">
<jaxrs:serviceBeans>
   <ref bean="agdRestfulService" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</jaxrs:extensionMappings>
<jaxrs:languageMappings>
<entry key="en" value="en-gb" />
</jaxrs:languageMappings>
</jaxrs:server>
</beans>
<span style="font-family: Arial, Helvetica, sans-serif;">web.xml</span>

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring_restful.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
 

以上已完成restful 服务开发

 

 

2.发布成https方式

 

tomcat 里server.xml 需要修改:

<!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->
<span style="white-space: pre;">	</span>
<span style="white-space: pre;">	</span><Connector
           protocol="org.apache.coyote.http11.Http11Protocol"
           port="8443" maxThreads="200"
           scheme="https" secure="true" SSLEnabled="true"
           <span style="color:#ff6666;">keystoreFile="d:\\tomcat.keystore" keystorePass="password"</span>
           clientAuth="false" sslProtocol="TLS"/>

 

 

 

 

keystoreFile为是生成密钥文件
keystorePass安全认证密码

以上tomcat 就可以起动了,正常情况 https服务就可以访问了。当然这里会报错,上面红色部分还没有完成.

 

 

 

3. jdk keytool 生成密钥和导入实例化信任库

 

 

keytool -genkey -alias tomcat -keyalg RSA -keypass password -storepass password -keystore d:\tomcat.keystore -validity 3600

password                      为密码。
d:\tomcat.keystore            生成的文件。

 


导入过程分2步,第一步是导出证书,

 

命令如下:keytool -export -trustcacerts -alias tomcat -file d:\tomcat.keystore.cer -keystore  tomcat.keystore -storepass password

 

 

 


第二步是导入到证书信任库,

 

 

 

命令如下:keytool -import -trustcacerts -alias tomcat -file d:\tomcat.keystore.cer -keystore  d:\tomcat.trustcacerts -storepass password

 

 

 

 

这样就完成 发布https 服务了。

 

 

4. 客户端应用 远程消费https 服务

 

package com.agd.https;


import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;


/**
 * 
 * 实现用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。
 * 
 * @author kuanghongjiang
 */
public class MyHostnameVerifier implements HostnameVerifier
{
    @Override
    public boolean verify(String hostname, SSLSession session)
    {
        if ("localhost".equals(hostname))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

 

package com.agd.client;


import com.agd.https.HttpsPostUtils;


/**
 * <一句话功能简述>
 * <功能详细描述>
 * 
 * @author kuanghongjiang
 * @version  [版本号, 2015年11月1日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class HttpsClient
{
    public static void main(String[] args)
    {
        // 取得认证
        HttpsPostUtils.initHTTPS();
        
        // 本地起的https服务
        
        String restgetTest = "https://localhost:8443/agdRestFul/services/restful/init/2222";
        
        String restpostTest = "https://localhost:8443/agdRestFul/services/restful/sendData";
        // 传输文本
        String xmlStr = "my https request";
        
        // 发起请求
        
        HttpsPostUtils.post(restpostTest, xmlStr);
        
        HttpsPostUtils.get(restgetTest, xmlStr);
    }
}

package com.agd.https;


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;


import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;


/**
 * HTTPS 请求工具类 <一句话功能简述> <功能详细描述>
 * 
 * @author kuanghongjiang
 * @version [版本号, 2015年11月1日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class HttpsPostUtils
{
    /**
     * 获得KeyStore.
     * 
     * @param keyStorePath 密钥库路径
     * @param password 密码
     * @return 密钥库
     * @throws Exception
     */
    public static KeyStore getKeyStore(String password, String keyStorePath)
        throws Exception
    {
        // 实例化密钥库
        KeyStore ks = KeyStore.getInstance("JKS");
        // 获得密钥库文件流
        FileInputStream is = new FileInputStream(keyStorePath);
        // 加载密钥库
        ks.load(is, password.toCharArray());
        // 关闭密钥库文件流
        is.close();
        return ks;
    }
    
    /**
     * 获得SSLSocketFactory.
     * 
     * @param password 密码
     * @param keyStorePath 密钥库路径
     * @param trustStorePath 信任库路径
     * @return SSLSocketFactory
     * @throws Exception
     */
    public static SSLContext getSSLContext(String password, String keyStorePath, String trustStorePath)
        throws Exception
    {
        // 实例化密钥库
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        // 获得密钥库
        KeyStore keyStore = getKeyStore(password, keyStorePath);
        // 初始化密钥工厂
        keyManagerFactory.init(keyStore, password.toCharArray());
        
        // 实例化信任库
        TrustManagerFactory trustManagerFactory =
            TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        // 获得信任库
        KeyStore trustStore = getKeyStore(password, trustStorePath);
        // 初始化信任库
        trustManagerFactory.init(trustStore);
        // 实例化SSL上下文
        SSLContext ctx = SSLContext.getInstance("TLS");
        // 初始化SSL上下文
        ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
        // 获得SSLSocketFactory
        return ctx;
    }
    
    /**
     * 初始化HttpsURLConnection.
     * 
     * @param password 密码
     * @param keyStorePath 密钥库路径
     * @param trustStorePath 信任库路径
     * @throws Exception
     */
    public static void initHttpsURLConnection(String password, String keyStorePath, String trustStorePath)
        throws Exception
    {
        // 声明SSL上下文
        SSLContext sslContext = null;
        // 实例化主机名验证接口
        HostnameVerifier hnv = new MyHostnameVerifier();
        try
        {
            sslContext = getSSLContext(password, keyStorePath, trustStorePath);
        }
        catch (GeneralSecurityException e)
        {
            e.printStackTrace();
        }
        if (sslContext != null)
        {
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        }
        HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    }
    
    /**
     * 发送请求.
     * 
     * @param httpsUrl 请求的地址
     * @param xmlStr 请求的数据
     */
    public static void post(String httpsUrl, String xmlStr)
    {
        HttpsURLConnection urlCon = null;
        try
        {
            urlCon = (HttpsURLConnection)(new URL(httpsUrl)).openConnection();
            urlCon.setDoInput(true);
            urlCon.setDoOutput(true);
            urlCon.setRequestMethod("POST");
            urlCon.setRequestProperty("Content-Length", "application/json");
            
            String param = "{\"username\":kuanghongjiang,\"password\":\"123456\"}";
            
            // urlCon.setUseCaches(false);
            // 设置为gbk可以解决服务器接收时读取的数据中文乱码问题
            
            OutputStream out = urlCon.getOutputStream();
            
            out.write(param.getBytes("gbk"));
            out.flush();
            
            if (urlCon.getResponseCode() != 200)
            {
                throw new RuntimeException("HTTPS POST Request Failed with Error code : " + urlCon.getResponseCode());
            }
            
            BufferedReader in = new BufferedReader(new InputStreamReader(urlCon.getInputStream()));
            String line;
            while ((line = in.readLine()) != null)
            {
                System.out.println(line);
            }
            
            // out.close();
        }
        catch (MalformedURLException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    
    /**
     * 发送请求. GET方式
     * 
     * @param httpsUrl 请求的地址
     * @param xmlStr 请求的数据
     */
    public static void get(String httpsUrl, String xmlStr)
    {
        HttpsURLConnection urlCon = null;
        try
        {
            urlCon = (HttpsURLConnection)(new URL(httpsUrl)).openConnection();
            urlCon.setDoInput(true);
            urlCon.setDoOutput(true);
            urlCon.setRequestMethod("GET");
            urlCon.setRequestProperty("Content-Length", "application/json");
            urlCon.setUseCaches(false);
            
            if (urlCon.getResponseCode() != 200)
            {
                throw new RuntimeException("HTTPS GET Request Failed with Error code : " + urlCon.getResponseCode());
            }
            
            BufferedReader in = new BufferedReader(new InputStreamReader(urlCon.getInputStream()));
            String line;
            while ((line = in.readLine()) != null)
            {
                System.out.println(line);
            }
        }
        catch (MalformedURLException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    
    public static void initHTTPS()
    {
        // 密码
        String password = "password";
        // 密钥库
        String keyStorePath = "F:\\project\\other\\tools\\tomcat\\apache-tomcat-8.0.21\\conf\\tomcat.keystore";
        // 信任库
        String trustStorePath = "F:\\project\\other\\tools\\tomcat\\apache-tomcat-8.0.21\\conf\\tomcat.trustcacerts";
        // 发起https 必要条件
        try
        {
            HttpsPostUtils.initHttpsURLConnection(password, keyStorePath, trustStorePath);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

 


使用客户端就能完成数据通信。

 

 

分布式这里就不说了,用ningx代理多台tomcat,之前有一片博文参考
 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值