Spring实现HTTPS双向认证

目录

前言

一、单向认证和双向认证

二、创建keyStore和trustStore

三、服务端配置

四、客户端配置 

总结

参考链接


前言

本篇博客讲的主要是双向认证,通过一些简单案例来展示双向认证的配置过程。有关单向认证和一些https配置,可以看看我的这篇博客,只有了解清楚单向认证之后,那么双向认证理解更加简单,因为双向认证基于单向认证配置,所以建议在做https双向认证之前,先把https单向认证搞清楚:

Spring实现HTTPS方式访问服务(单向认证)_明天再去学习的博客-CSDN博客

 


一、单向认证和双向认证

1、单向认证

单向认证十分简单,就是在服务端配置证书,客户端在向服务端发送请求时,服务端会发送一份自己的证书,由客户端进行验证,只要客户端通过验证,那么就能建立https链接。

2、双向认证

双向认证相比于单向认证多了一个步骤,那就是客户端发送请求时校验服务端的证书的同时,客户端也需要发送一份自己的证书给服务端进行校验,只有双方的证书在对方那里校验通过之后,才能建立起https链接。

二、创建keyStore和trustStore

1、keyStore与trustStore的作用

keyStore:

  • keyStore是一个可以存储密钥、密钥对或证书的存储库。密钥:只有一个钥,一般是对称加密时使用;密钥对:包含公钥和私钥,一般是非对称加密时使用。
  • keyStore文件的类型可以是JSK、PKCS12、JCEKS。JSK(Java Key Store)可以存储密钥对和证书;PKCS12、JCEKS都可以存储密钥、密钥对、证书。
  • 在创建keyStore文件时,可以为keyStore设置密码。
  • 密钥、密钥对、证书在keyStore统称为key,每一个key通过alias(别名)区分。key也可以设置密码(具体体现在keytool创建keyStore和trustStore时),keyStore可以存储多对key。
  • 通过keytool成功往一个keyStore文件添加密钥对后,可以从该keyStore中获取到私钥、证书以及公钥(公钥主要以证书的形式存放)。

trustStore:

  •  trustStore中保存的是一些可信任的证书
  • trustStore文件的类型可以是JSK、PKCS12、JCEKS。JSK(Java Key Store)可以存储密钥对和证书;PKCS12、JCEKS都可以存储密钥、密钥对、证书。

2、创建服务端keyStore和客户端trustStore(以下指令均在控制台执行)

注意:由于只是本地简单配置双向认证,涉及到的证书将由工具keytool生成,真正生产环境下的证书,将有认证过的CA机构去生成。

创建服务端keyStore

keytool -genkey -alias serverkey -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore serverkeystore.p12 -storepass 123456 -ext san=ip:127.0.0.1,dns:localhost

导出服务端证书

keytool -exportcert -keystore serverkeystore.p12 -alias serverkey -storepass 123456 -rfc -file server-certificate.pem

将服务端证书添加到客户端trustStore中 

keytool -import -trustcacerts -file server-certificate.pem -keypass 123456 -storepass 123456 -keystore clienttruststore.jks

3、创建客户端keyStore和服务端trustStore 

 创建客户端keyStore

keytool -genkey -alias client -keyalg RSA -keysize 2048 -sigalg SHA256withRSA -keystore clientKeystore.p12 -storepass 123456 -ext san=ip:127.0.0.1

导出客户端证书

keytool -exportcert -keystore clientKeystore.p12 -alias client -storepass 123456 -rfc -file client-certificate.pem

将客户端证书添加到服务端trustStore中 

keytool -import -trustcacerts -file client-certificate.pem -keypass 123456 -storepass 123456 -keystore serverTruststore.jks

4、生成结果

 

在后续实践中,我们需要用到的是 serverKeyStore、serverTrustStore、clientKeyStore、clientTrustStore

 

三、服务端配置

1、将serverKeyStore、serverTrustStore存放在resource目录下

2、application.yml配置如下

server:
  port: 7050
  ssl:
    key-store: classpath:serverKeyStore.p12
    key-store-password: 123456
    key-store-type: PKCS12
    key-alias: serverKey
    client-auth: need
    trust-store: classpath:serverTrustStore.jks
    trust-store-password: 123456
    trust-store-type: JKS
  • key-store:用于指定你的keyStrore文件
  • key-store-type:指定你的文件的类型,在上面说过,keyStore的类型可以是JKS、PKCS12、JCEKS
  • key-store-password:就是你在通过keytool创建keyStore时指定的密码
  • key-alias: 指定使用哪一个key
  • client-auth:开启客户端验证,即需要验证客户端证书,服务端开启双向认证的开关
  • trust-store:用于指定你的trustStrore(信任库)文件,客户端证书校验将在此处进行
  • trust-store-type:指定你的文件的类型,在上面说过,trustStore的类型可以是JKS、PKCS12、JCEKS
  • trust-store-password:就是你在通过keytool创建trustStore时指定的密码

至此,服务端https双向认证配置到此处结束,接下来是客户端的配置

 

四、客户端配置 

1、将clientKeyStore、clientTrustStore存放在resource目录下:

 

2、导入以下依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.6</version>
</dependency>

 

3、进行RestTemplate配置:

@Slf4j
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory httpComponentsClientHttpRequestFactory) {
        RestTemplate restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory);
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }

    @Bean("httpComponentsClientHttpRequestFactory")
    public ClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        final String allPassword = "123456";
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
        SSLContext sslContext = SSLContextBuilder
                .create()
                .loadKeyMaterial(new ClassPathResource("clientKeystore.p12").getURL(),
                        allPassword.toCharArray(), allPassword.toCharArray())
                .loadTrustMaterial(new ClassPathResource("clientTruststore.jks").getURL(), allPassword.toCharArray())
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
        HttpClient client = HttpClients.custom()
                .setSSLContext(sslContext)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);
        // INSTANCE 忽略域名检查,证书中的域名与请求的域名不匹配时,验证通过, 不建议开启该功能,因为存在安全问题
       /*SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        CloseableHttpClient httpclient = HttpClients
                .custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setSSLHostnameVerifier(new NoopHostnameVerifier())
                .build();
        requestFactory.setHttpClient(httpclient);*/
        return requestFactory;
    }

}

 4、通过RestTempate进行接口调用,客户端能够与开启双向认证后的服务端进行连接访问。

至此,客户端的配置也完成了 。


总结

双向配置的精髓就是,客户端也需要配置自己的证书,在发送请求的同时,将自己的证书发送给服务端,让服务端去验证证书,所以,搞清楚双向认证配置之前,一定要先弄清楚单向认证配置,以达事半功倍。

参考链接

一文读懂Https的安全性原理、数字证书、单项认证、双项认证等 - 知乎

百度安全验证 

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Security是一个功能强大的身份认证和授权框架,它可以帮助我们在Spring应用程序中实现安全性。下面是Spring Security实现身份认证的一般步骤: 1. 添加Spring Security依赖:在项目的构建文件中添加Spring Security的依赖,例如在Maven项目中可以添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 配置Spring Security:创建一个配置类,继承自`WebSecurityConfigurerAdapter`,并重写`configure`方法来配置安全性规则。在该方法中,可以定义哪些URL需要进行身份认证,以及使用哪种认证方式等。例如: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/home") .permitAll() .and() .logout() .logoutUrl("/logout") .permitAll(); } } ``` 3. 自定义用户认证实现`UserDetailsService`接口,并重写`loadUserByUsername`方法来自定义用户认证逻辑。在该方法中,可以根据用户名从数据库或其他数据源中获取用户信息,并返回一个实现了`UserDetails`接口的对象。例如: ```java @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User not found"); } return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.getAuthorities() ); } } ``` 4. 配置密码加密:为了保护用户密码的安全性,可以配置密码加密方式。可以使用Spring Security提供的各种加密器,例如BCryptPasswordEncoder。在配置类中添加一个`PasswordEncoder`的Bean,并在`configure`方法中使用该加密器对密码进行加密。例如: ```java @Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } } ``` 这样,当用户访问需要认证的URL时,Spring Security会自动进行身份认证,并根据配置的规则进行授权。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值