springboot项目开启ssl双向认证且实现相互访问通信浏览器访问通信

在这里插入图片描述

制作证书

命令制作用于SSL/TSL的证书

1、服务器端===>生成自签名证书**

keytool -genkeypair -keyalg RSA -keysize 2048 -keystore d:/server.jks -alias server -validity 365 -keypass 123456 -storepass 123456 -dname "CN=localhost" -ext san=IP:192.168.1.9

这段命令是使用Java的keytool工具生成一个RSA算法的密钥对,并将其保存在名为server.jks的密钥库文件中。以下是各个参数的解释:

  • -genkeypair:生成密钥对的命令。
  • -keyalg RSA:指定使用RSA算法生成密钥对。
  • -keysize 2048:指定生成的密钥长度为2048位。
  • -keystore d:/server.jks:指定保存生成的密钥对的密钥库文件路径为d:/server.jks。
  • -alias server:指定生成的密钥对的别名为server。
  • -validity 365:指定生成的证书的有效期为365天。
  • -keypass 123456:指定生成的密钥对的密码为123456。
  • -storepass 123456:指定密钥库文件的密码为123456。
  • -dname “CN=localhost”:指定生成的证书的Distinguished Name(DN),包括Common Name(CN),这里设置为localhost。
  • -ext san=IP:192.168.1.9:添加Subject Alternative Name(SAN)扩展,指定证书的主体为IP地址192.168.1.9。
    通过这个命令,将生成一个包含RSA密钥对的密钥库文件,并且生成一个证书,该证书中包含了服务器的IP地址192.168.1.9作为主体。这个证书可以用于配置服务器端的SSL/TLS通信,以确保通信的安全性。

2、服务器端===>从服务器端证书秘钥库中导出Cer证书**

keytool -export -alias server -keystore d:/server.jks -storepass 123456 -file d:/server.cer

上面的命令使用keytool工具从server.jks keystore中导出server别名的证书,并保存为server.cer文件。以下是命令的详细说明:

  • -export:指定要执行导出操作。
  • -alias server:指定要导出的证书的别名为server。
  • -keystore d:/server.jks:指定要导出证书的keystore文件路径为d:/server.jks。
  • -storepass 123456:指定keystore的密码为123456。
  • -file d:/server.cer:指定导出的证书保存的文件路径为d:/server.cer。
    执行该命令后,会将server.jks keystore中server别名的证书导出为server.cer文件。这个导出的证书文件可以用于配置服务器端以进行SSL双向认证,或者用于其他需要验证证书的场景。请确保妥善保管导出的证书文件,以确保通信的安全性。

3、客户端==>生成自签名证书**

keytool -genkeypair -keyalg RSA -keysize 2048 -keystore d:/client.jks -alias client -validity 365 -keypass 123456 -storepass 123456 -dname "CN=localhost" -ext san=IP:192.168.1.9

这段命令与上一个命令类似,也是使用Java的keytool工具生成一个RSA算法的密钥对,并将其保存在名为client.jks的密钥库文件中。以下是各个参数的解释:

  • -genkeypair:生成密钥对的命令。
  • -keyalg RSA:指定使用RSA算法生成密钥对。
  • -keysize 2048:指定生成的密钥长度为2048位。
  • -keystore d:/client.jks:指定保存生成的密钥对的密钥库文件路径为d:/client.jks。
  • -alias client:指定生成的密钥对的别名为client。
  • -validity 365:指定生成的证书的有效期为365天。
  • -keypass 123456:指定生成的密钥对的密码为123456。
  • -storepass 123456:指定密钥库文件的密码为123456。
  • -dname “CN=localhost”:指定生成的证书的Distinguished Name(DN),包括Common Name(CN),这里设置为localhost。
  • -ext san=IP:192.168.1.9:添加Subject Alternative Name(SAN)扩展,指定证书的主体为IP地址192.168.1.9。
    通过这个命令,将生成一个包含RSA密钥对的密钥库文件,并且生成一个证书,该证书中包含了客户端的IP地址192.168.1.9作为主体。这个证书可以用于配置客户端的SSL/TLS通信,以确保通信的安全性。

4、客户端==>从服务器端证书秘钥库中导出Cer证书**

keytool -export -alias client -keystore d:/client.jks -storepass 123456 -file d:/client.cer

上面的命令使用keytool工具从client.jks keystore中导出client别名的证书,并保存为client.cer文件。以下是命令的详细说明:

  • -export:指定要执行导出操作。
  • -alias client:指定要导出的证书的别名为client。
  • -keystore d:/client.jks:指定要导出证书的keystore文件路径为d:/client.jks。
  • -storepass 123456:指定keystore的密码为123456。
  • -file d:/client.cer:指定导出的证书保存的文件路径为d:/client.cer。
    执行该命令后,会将client.jks keystore中client别名的证书导出为client.cer文件。这个导出的证书文件可以用于配置客户端以进行SSL双向认证,或者用于其他需要验证证书的场景。请确保妥善保管导出的证书文件,以确保通信的安全性。

5、客户端==>将客户端证书导入到服务器端证书秘钥库**

keytool -import -trustcacerts -alias server -file d:/server.cer -keystore d:/client.jks -storepass 123456

上面的命令使用keytool工具将名为server.cer的服务器证书导入到client.jks证书库中。以下是命令的详细说明:

  • -import:指定要执行导入操作。
  • -trustcacerts:指定将证书视为受信任的CA证书。
  • -alias server:指定要为导入证书指定的别名为server。
  • -file d:/server.cer:指定要导入的证书文件路径为d:/server.cer。
  • -keystore d:/client.jks:指定要导入证书的证书库文件路径为d:/client.jks。
  • -storepass 123456:指定证书库的密码为123456。
    执行该命令后,会将名为server.cer的服务器证书导入到client.jks证书库中,并分配别名为server。这样,客户端client就可以使用这个证书来验证服务器的身份。请确保导入的证书文件和密码的安全性,以确保通信的安全性。

6、服务器端==>将服务器端证书导入到客户端证书秘钥库**

keytool -import -trustcacerts -alias client -file d:/client.cer -keystore d:/server.jks -storepass 123456

在这个命令中,您使用keytool工具将名为client.cer的客户端证书导入到server.jks证书库中。以下是命令的详细说明:

  • -import:指定要执行导入操作。
  • -trustcacerts:指定将证书视为受信任的CA证书。
  • -alias client:指定要为导入证书指定的别名为client。
  • -file d:/client.cer:指定要导入的证书文件路径为d:/client.cer。
  • -keystore d:/server.jks:指定要导入证书的证书库文件路径为d:/server.jks。
  • -storepass 123456:指定证书库的密码为123456。
    执行该命令后,会将名为client.cer的客户端证书导入到server.jks证书库中,并分配别名为client。这样,服务器端server就可以使用这个证书来验证客户端client的身份。请确保导入的证书文件和密码的安全性,以确保通信的安全性。

7、将客户端导出浏览器可安装的证书**

keytool -importkeystore -srckeystore d:/client.jks -destkeystore d:/client.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass 123456 -deststorepass 123456 -srckeypass 123456 -destkeypass 123456 -srcalias client -destalias client -noprompt

在这个命令中,您使用keytool工具将名为client.jks的Java密钥库(JKS)转换为名为client.p12的PKCS12格式的密钥库。以下是命令的详细说明:

  • -importkeystore:指定要执行密钥库转换操作。
  • -srckeystore client.jks:指定要转换的源密钥库文件路径为client.jks。
  • -destkeystore client.p12:指定要生成的目标密钥库文件路径为client.p12。
  • -srcstoretype JKS:指定源密钥库的类型为JKS。
  • -deststoretype PKCS12:指定目标密钥库的类型为PKCS12。
  • -srcstorepass 123456:指定源密钥库的密码为123456。
  • -deststorepass 123456:指定目标密钥库的密码为123456。
  • -srckeypass 123456:指定源密钥库中密钥的密码为123456。
  • -destkeypass 123456:指定目标密钥库中密钥的密码为123456。
  • -srcalias client:指定要转换的源密钥库中的别名为client。
  • -destalias client:指定在目标密钥库中为转换后的别名为client。
  • -noprompt:禁止提示用户输入任何信息,以便自动执行转换操作。
    执行该命令后,将会将client.jks的密钥库转换为client.p12的PKCS12格式的密钥库,并分配别名为client。请确保密码的安全性,以确保密钥库的安全性。

8、将服务端导出浏览器可安装的证书**

keytool -importkeystore -srckeystore d:/server.jks -destkeystore d:/server.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass 123456 -deststorepass 123456 -srckeypass 123456 -destkeypass 123456 -srcalias server -destalias server -noprompt

在这个命令中,您使用keytool工具将名为server.jks的Java密钥库(JKS)转换为名为server.p12的PKCS12格式的密钥库。以下是命令的详细说明:

  • -importkeystore:指定要执行密钥库转换操作。
  • -srckeystore server.jks:指定要转换的源密钥库文件路径为server.jks。
  • -destkeystore server.p12:指定要生成的目标密钥库文件路径为server.p12。
  • -srcstoretype JKS:指定源密钥库的类型为JKS。
  • -deststoretype PKCS12:指定目标密钥库的类型为PKCS12。
  • -srcstorepass 123456:指定源密钥库的密码为123456。
  • -deststorepass 123456:指定目标密钥库的密码为123456。
  • -srckeypass 123456:指定源密钥库中密钥的密码为123456。
  • -destkeypass 123456:指定目标密钥库中密钥的密码为123456。
  • -srcalias server:指定要转换的源密钥库中的别名为server。
  • -destalias server:指定在目标密钥库中为转换后的别名为server。
  • -noprompt:禁止提示用户输入任何信息,以便自动执行转换操作。
    执行该命令后,将会将server.jks的密钥库转换为server.p12的PKCS12格式的密钥库,并分配别名为server。请确保密码的安全性,以确保密钥库的安全性。

查看颁发证书

此步只是为了检查证书的内容,jks的信任库中是否存在对方秘钥。

keytool -list -v -keystore d:/server.jks -storepass 123456
keytool -list -v -keystore d:/client.jks -storepass 123456

最后生成的文件:

在这里插入图片描述

springboot项目配置

项目application.yml文件配置

服务端:

server:
  port: 2222
  ssl:
    key-store: D://server.jks
    key-store-password: 123456
    key-alias: server
    trust-store: D://server.jks
    trust-store-password: 123456
    #是否需要进行认证
    client-auth: need

客户端:

server:
  port: 3333
  ssl:
    key-store: D://client.jks
    key-store-password: 123456
    key-alias: server
    trust-store: D://client.jks
    trust-store-password: 123456
    #是否需要进行认证
    client-auth: need

解释:

  • server.port: 2222:指定了应用的服务器端口号为2222。
  • server.ssl.key-store: classpath:server.jks:指定了SSL连接使用的服务器端证书存储路径为classpath:server.jks,即在classpath下的server.jks文件。
  • server.ssl.key-store-password: 123456:指定了服务器端证书存储文件的密码为123456。
  • server.ssl.key-alias: server:指定了服务器端证书的别名为server。
  • server.ssl.trust-store: classpath:server.jks:指定了SSL连接使用的客户端信任库路径为classpath:server.jks,即在classpath下的server.jks文件。
  • server.ssl.trust-store-password: 123456:指定了客户端信任库文件的密码为123456。
  • server.ssl.client-auth: need:指定了客户端需要进行双向认证,即客户端需要提供证书进行身份验证。

controller编写

服务端:

@RestController("/")
public class HelloWorld {
    @RequestMapping("/")
    public String hello(){
        return "这是服务端后台:你好世界!";
    }

    @Autowired
    RestTemplate restTemplate;
    @GetMapping("/test")
    public String sendRequest() {
        String url = "https://192.168.1.9:3333"; // 替换为接收请求的项目的API接口地址
        String forObject = restTemplate.getForObject(url, String.class);
        return "服务端访问客户端》》》"+forObject;
    }
}

客户端:

@RestController("/")
public class HelloWorld {
    @RequestMapping("/")
    public String hello(){
        return "这是客户端后台:你好世界!";
    }

    @Autowired
    RestTemplate restTemplate;
    @GetMapping("/test")
    public String sendRequest() {
        String url = "https://192.168.1.9:2222"; // 替换为接收请求的项目的API接口地址
        String forObject = restTemplate.getForObject(url, String.class);
        return "客户端访问服务端》》》"+forObject;
    }
}

浏览器测试

先启动刚配置好的springboot服务**

在浏览器访问服务端https://192.168.1.9:2222 浏览器提示不接受您的登录证书,或者您可能没有提供登录证书。
在这里插入图片描述

在浏览器中点击设置——》搜索SSL——》进入安全——》点击管理您设备上的 HTTPS/SSL 证书
在这里插入图片描述

点击导入——》筛选个人信息交换——》选择client.p12文件——》打开
在这里插入图片描述

下一步输入证书密码123456——》默认下一步即可添加成功 如图:
在这里插入图片描述

重新刷新浏览器https://192.168.1.9:2222——选择确认证书即可成功访问
在这里插入图片描述
在浏览器访问客户端是一样的操作https://192.168.1.9:3333 浏览器提示不接受您的登录证书,或者您可能没有提供登录证书将server.p12文件证书导入即可。

main方法测试

下面这两段代码是用来测试使用,不加入springboot项目中,仅测试使用证书与客户端、服务端是否可以握手成功。
客户端访问服务端 使用客户端证书

public static void main(String[] args) throws Exception{
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream(new File("D://client.jks")), "123456".toCharArray());

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream(new File("D://client.jks")), "123456".toCharArray());

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(keyStore, "123456".toCharArray())
                .loadTrustMaterial(trustStore, null)
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)//禁用主体名》当制作证书的主体名是随便写的,握手时一定会报报主体名问题,此时可以先禁用主体名。
                .build();

        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        RestTemplate restTemplate= new RestTemplate(requestFactory);
        String forObject = restTemplate.getForObject("https://192.168.1.9:2222", String.class);
        System.out.println("测试访问》》》"+forObject);;

    }

服务端访问客户端 使用服务端证书

public static void main(String[] args) throws Exception{
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream(new File("D://server.jks")), "123456".toCharArray());

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream(new File("D://server.jks")), "123456".toCharArray());

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(keyStore, "123456".toCharArray())
                .loadTrustMaterial(trustStore, null)
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)//禁用主体名》当制作证书的主体名是随便写的,握手时一定会报报主体名问题,此时可以先禁用主体名。
                .build();

        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        RestTemplate restTemplate= new RestTemplate(requestFactory);
        String forObject = restTemplate.getForObject("https://192.168.1.9:3333", String.class);
        System.out.println("测试访问》》》"+forObject);;

    }

到了这一步说明证书配置没有问题,双向认证也是通的。

springboot项目间SSL双重认证相互访问

springboot项目之间双向认证的互相通信主要在请求时有所变化:

客户端访问服务端的RestTemplate

@Configuration
public class RestConfig {
    @Bean
    public RestTemplate restTemplate() throws Exception {
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream(new File("D://client.jks")), "123456".toCharArray());

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream(new File("D://client.jks")), "123456".toCharArray());

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(keyStore, "123456".toCharArray())
                .loadTrustMaterial(trustStore, null)
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)//禁用主体名》当制作证书的主体名是随便写的,握手时一定会报报主体名问题,此时可以先禁用主体名。
                .build();

        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(requestFactory);
    }

}

服务端访问客户端的RestTemplate

@Configuration
public class RestConfig {
    @Bean
    public RestTemplate restTemplate() throws Exception {
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream(new File("D://server.jks")), "123456".toCharArray());

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream(new File("D://server.jks")), "123456".toCharArray());

        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(keyStore, "123456".toCharArray())
                .loadTrustMaterial(trustStore, null)
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(sslContext)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)//禁用主体名》当制作证书的主体名是随便写的,握手时一定会报报主体名问题,此时可以先禁用主体名。
                .build();

        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(requestFactory);
    }

}

验证是否正确通信

浏览器中访问https://192.168.1.9:2222/test查看结果:
在这里插入图片描述

浏览器中访问https://192.168.1.9:3333/test查看结果:
在这里插入图片描述

按照自己想法来 使用RestTemplate正常去访问对方的服务即可。

源代码已上传SCDN:

https://download.csdn.net/download/YnagLei/88914176

Spring Boot 配置WebSocket SSL双向认证通常涉及到以下几个步骤: 1. **添加依赖**:首先,在`pom.xml`或`build.gradle`文件中添加WebSocket相关的Spring Websocket依赖,以及支持SSL/TLS的Spring Security依赖。 ```xml <!-- Maven --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Gradle (Kotlin) --> implementation("org.springframework.boot:spring-boot-starter-websocket") implementation("org.springframework.boot:spring-boot-starter-security") ``` 2. **创建SSL证书**:生成一对公钥私钥对,比如使用`keytool`工具。在命令行运行类似下面的命令: ```sh keytool -genkey -alias server-cert -keyalg RSA -keystore keystore.jks -storepass password -keypass password ``` 3. **配置服务器端点**:在`Application.java`或其他启动类里,启用WebSocket并设置HTTPS监听: ```java @Configuration @EnableWebSockets public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { // ... } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket").withSockJS(); } @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainer container = new StandardServletWebSocketContainer(); container.setSecure(true); // 使用HTTPS // 如果需要SSLEngine设置,请在这里配置 return container; } } ``` 4. **配置Spring Security**:在`SecurityConfig`类中,启用WebSocket安全,并指定客户端证书验证: ```java @Configuration @EnableWebSecurity @EnableWebsocketAuthentication public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CertificateAuthenticationProvider certificateAuthProvider; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/ws/**").authenticated() .anyRequest().permitAll(); // 可能需要根据实际需求调整 http.certificateBasedAuthentication() .authenticationManager(authenticationManager()) .and() .apply(securityConfigurerAdapter); } @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return new DefaultWebSecurityConfigurerAdapter().authenticationManager(); } @Override protected void configure(WebSocketSecurity web) throws Exception { web.authorizeRequests() .anyMessage().authenticated() .and() .addCustomizer(new WebSocketSessionManagementExtensionAdapter(certificateAuthProvider)); } } ``` 5. **提供证书**:将生成的keystore文件放在应用目录下,并在`application.properties`或`application.yml`中指定路径: ```properties server.ssl.key-store=classpath:keystore.jks server.ssl.key-store-password=password server.ssl.trust-store=classpath:truststore.jks server.ssl.trust-store-password=password ``` 6. **启动应用并测试**:启动Spring Boot应用,客户端连接到HTTPS地址,并提供正确的证书进行验证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值