详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt386

本文介绍如何让基于Spring的REST服务变得SSL/TSL化。

首先,假设一个Spring REST 服务如下:

1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping("/")
public class RestService {
    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String get() {
        return "Called the get Rest Service";
    }
}

 Web.xml的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<web-app
    version="3.1"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
  
    <servlet>
        <servlet-name>rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.radcortez.rest.ssl</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
  
    <servlet-mapping>
        <servlet-name>rest</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Rest Application</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <!-- Needed for our application to respond to https requests -->
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
</web-app>

 注意其中security-constraintuser-data-constraint 和 <transport-guarantee>CONFIDENTIAL</transport-guarantee>配置,这些指定这个应用需要一个安全连接。

 运行这个服务,部署应用到TomEE,键入网址:https://localhost:8443/,如果你正常配置了tomcat的SSL配置,浏览https和端口844应该一切正常,返回:Called the Rest Service

 如果现在调用客户端不是一般浏览器,而是一个Java客户端,这时会抛出错误:

Message: I/O error on GET request for "https://localhost:8443/":sun.security.validator.ValidatorException:

Exception: Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

 这是因为客户端JDK并没有你服务器的证书,你需要导入,这里我们展示使用编程方式提供信任蜜月的方式,这样做的好处:

  • 你可以运行应用代码在多个环境(和JDK无关)

  • 你不必每次手工将证书导入JDK

  • 你也不必升级JDK时得记住你的证书

  • 其他原因导致你不能直接向JDK导入证书

 编写代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
RestClientConfig.java
@Configuration
@PropertySource("classpath:config.properties")
public class RestClientConfig {
    @Bean
    public RestOperations restOperations(ClientHttpRequestFactory clientHttpRequestFactory) 
    throws Exception {
        return new RestTemplate(clientHttpRequestFactory);
    }
  
    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
        return new HttpComponentsClientHttpRequestFactory(httpClient);
    }
  
    @Bean
    public HttpClient httpClient(@Value("${keystore.file}") String file,
                                 @Value("${keystore.pass}") String password)
                                  throws Exception {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream instream = new FileInputStream(new File(file));
        try {
            trustStore.load(instream, password.toCharArray());
        finally {
            instream.close();
        }
  
        SSLContext sslcontext =
                SSLContexts.custom()
                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
        SSLConnectionSocketFactory sslsf =
                new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null,
                                               BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }
  
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

这里我们使用Spring RestOperations接口规定一个RESTful操作的基本集合,下面我们使用Apache HTTP组件SSLConnectionSocketFactory 提供的功能来校验服务器的信任密钥,也是使用服务器的 KeyStore

RestServiceClientIT.java

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = RestClientConfig.class)
public class RestServiceClientIT {
    @Autowired
    private RestOperations rest;
  
    @Test
    public void testRestRequest() throws Exception {
        ResponseEntity response = rest.getForEntity("https://localhost:8443/", String.class);
        System.out.println("response = " + response);
        System.out.println("response.getBody() = " + response.getBody());
    }
}

上面是一个简单的测试类,我们需要一个属性文件提供keystore文件位置和密码:

config.properties

keystore.file=${user.home}/.keystore

keystore.pass=changeit

 现在我们可以运行测试客户端,你应该得到如下:

Response: <200 OK,Called the get Rest Service,{Server=[Apache-Coyote/1.1], Cache-Control=[private], Expires=[Thu, 01 Jan 1970 01:00:00 WET], Content-Type=, Content-Length=[27], Date=[Tue, 23 Dec 2014 01:29:20 GMT]}>

Body: Called the get Rest Service

 这说明一切正常,现在,你可以使用Java客户端以SSL/TLS方式调用你的REST服务了。

实现Spring RESTful服务的SSL的更多相关文章

  1. Spring RESTful服务接收和返回JSON最佳实践

    http://blog.csdn.net/prince_hua/article/details/12103501

  2. 使用Spring Security Oauth2完成RESTful服务password认证的过程

            摘要:Spring Security与Oauth2整合步骤中详细描述了使用过程,但它对于入门者有些重量级,比如将用户信息.ClientDetails.token存入数据库而非内存.配置 ...

  3. 应用Spring MVC发布restful服务是怎样的一种体验

            摘要:“约定优于配置”这是一个相当棒的经验,SOAP服务性能差.基于配置.紧耦合,restful服务性能好.基于约定.松耦合,现在我就把使用Spring MVC发布restful服务的 ...

  4. Spring Boot初探之restful服务发布

    一.背景 Spring boot是集服务发布.数据库管理.日志管理等于一身的服务开发框架:是微服务开发的全能小帮手.这章讲述一下如何使用spring boot发布restful服务接口. 二.搭建基础 ...

  5. 用Kotlin写一个基于Spring Boot的RESTful服务

    Spring太复杂了,配置这个东西简直就是浪费生命.尤其在没有什么并发压力,随便搞一个RESTful服务 让整个业务跑起来先的情况下,更是么有必要纠结在一堆的XML配置上.显然这么想的人是很多的,于是 ...

  6. CXF+Spring+JAXB+Json构建Restful服务

    话不多说,先看详细的样例: 文件文件夹结构: web.xml <?xml version="1.0" encoding="UTF-8"? > < ...

  7. 使用spring mvc或者resteasy构建restful服务

    看到最近一个项目里用resteasy来构建restful接口,有点不明白,不少Spring mvc4.0以后也可以很方面的实现restful服务吗,为啥还要在Spring MVC的项目里还引入rest ...

  8. 实战SpringCloud响应式微服务系列教程(第九章)使用Spring WebFlux构建响应式RESTful服务

    本文为实战SpringCloud响应式微服务系列教程第九章,讲解使用Spring WebFlux构建响应式RESTful服务.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 从本节开始我们 ...

  9. HTTP RESTful服务开发 spring boot+Maven +Swagger

    这周配合第三方平台整合系统,需要提供HTTP REST服务和使用ActiveMQ推送消息,研究了下,做个笔记. 1.使用eclipse创建Spring Boot项目  创建Spring Boot项目( ...

随机推荐

  1. 如何使用Androidstudio创建一个新项目

    首先打开AS,然后 选择第一个选项Start a new Android Studio project 填写包名和项目名,点击next 选择项目类型,点击next 选择UI类型(都是死丢丢帮你生成的) ...

  2. vue指令v-pre示例解析

    v-pre会跳过该元素及其子元素的编译过程,显示原始标签. <div id="app"> <span v-pre>{{msg}} 这句不会编译</sp ...

  3. 只需要一点点C++基础,新手也可以制作单机游戏内存修改器

    声明:本文只是为了初学C++的,能够做出一些实用的东西,跳出管理系统的束缚,提升学习的兴趣,在这里选取了单机游戏,请不要尝试在线游戏,违发而已未必可行.序:首先我们需要一个Qt+VS环境Qt从http ...

  4. 关于Web.config的debug和release.config文件

    使用Web.Config Transformation配置灵活的配置文件 发布Asp.net程序的时候,开发环境和发布环境的Web.Config往往不同,比如connectionstring等.如果常 ...

  5. 安徽省2016“京胜杯”程序设计大赛_H_单身晚会

    单身晚会 Time Limit: 1000 MS Memory Limit: 65536 KB Total Submissions: 53 Accepted: 16 Description ​ZJ和Z ...

  6. java运算符优先级与流程控制

    1. Java 的方法Method (函数 Function), 功能, 动作 1) 方法就是函数: y=f(x)=3x+6; 2) 方法的语法   (修饰词)(返回值类型)(方法名)(参数列表){  ...

  7. macvlan 网络结构分析 - 每天5分钟玩转 Docker 容器技术(56)

    上一节我们创建了 macvlan 并部署了容器,本节详细分析 macvlan 底层网络结构. macvlan 网络结构分析 macvlan 不依赖 Linux bridge,brctl show 可以 ...

  8. 社交系统/社群系统“ThinkSNS+”H5及PC端终于来了!一起来“找茬”

    [什么是TS+?] ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+,简称TS+. 还记得2017年 ...

  9. RabbitMQ --- Publish/Subscribe(发布/订阅)

    目录 RabbitMQ --- Hello Mr.Tua RabbitMQ --- Work Queues(工作队列) 前言 在第二篇文章中介绍了 Work Queues(工作队列),它适用于把一个消 ...

  10. pthread创建线程的简单演示

      使用pthread创建子线程的简单步骤 导入头文件 #import <pthread.h> 指定新线程标识符 使用pthread创建线程的函数 根据result = 0 与否判断子线程 ...