• https单向认证和双向认证demo(SpringBoot+okhttp3+keytool自签名)


    目录

    一、前言

    二、软件版本

    三、单向认证

    四、双向认证

    一、前言
    HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1] 。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。

    本文使用okhttp3访问SpringBoot创建的https接口。

    二、软件版本
    SpringBoot:2.1.2

    okhttp3:3.2.0

    keytool:jdk1.8.0_77

    三、单向认证
    1生成服务端证书

    keytool -genkey -alias server -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\Users\admin\Desktop\server.p12

    记住秘钥库口令,在SpringBoot配置中使用

    2导出服务端cer证书

    keytool -export -alias server -keystore C:\Users\admin\Desktop\server.p12 -storetype PKCS12 -keypass 123456 -file C:\Users\admin\Desktop\server.cer

    3配置SpringBoot

    将server.p12拷贝到SpringBoot的resources目录

    #ssl配置
    server.ssl.enabled=true
    server.ssl.key-store=classpath:server.p12
    server.ssl.key-store-password=123456
    server.ssl.key-store-type=JKS
    # 证书别名
    server.ssl.key-alias=server
    4浏览器测试

    访问https://localhost:8080/demo

     

    5okhttp3测试

    path:者指定server.cer的路径

    package com.asyf.demo.other_api.okhttp3;

    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;

    import javax.net.ssl.*;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.security.KeyStore;
    import java.security.SecureRandom;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;

    /**
    * https单向认证
    */
    public class Test2 {

    //安全传输层协议
    private static final String PROTOCOL = "TLS";

    // JKS/PKCS12
    private static final String KEY_KEYSTORE_TYPE = "PKCS12";

    private static SSLSocketFactory getSocketFactory(String cerPath) throws Exception {
    SSLSocketFactory socketFactory = null;
    try (InputStream cerInputStream = new FileInputStream(new File(cerPath))) {
    TrustManager[] trustManagers = getTrustManagers(cerInputStream);
    SSLContext sslContext = getSslContext(trustManagers);
    socketFactory = sslContext.getSocketFactory();
    }
    return socketFactory;
    }

    private static SSLContext getSslContext(TrustManager[] trustManagers) throws Exception {
    SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
    sslContext.init(null, trustManagers, new SecureRandom());
    return sslContext;
    }

    private static TrustManager[] getTrustManagers(InputStream inputStream) throws Exception {
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);
    //加载证书
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    Certificate ca = certificateFactory.generateCertificate(inputStream);
    keyStore.load(null, null);
    //设置公钥
    keyStore.setCertificateEntry("server", ca);
    trustManagerFactory.init(keyStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    return trustManagers;
    }

    public static void main(String[] args) throws Exception {
    //获取SSLSocketFactory
    String certPath = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\server.cer";//服务端公钥
    SSLSocketFactory socketFactory = getSocketFactory(certPath);
    //发送请求
    String url = "https://127.0.0.1:8080/demo";
    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
    clientBuilder.sslSocketFactory(socketFactory);
    //解决报错javax.net.ssl.SSLPeerUnverifiedException: Hostname 127.0.0.1 not verified
    clientBuilder.hostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String s, SSLSession sslSession) {
    System.out.println("主机:" + s);
    return true;
    }
    });
    OkHttpClient client = clientBuilder.build();

    Request.Builder builder = new Request.Builder().url(url);
    Request request = builder.build();

    Response response = client.newCall(request).execute();
    String result = response.body().string();
    //打印请求结果
    System.out.println(result);
    }

    }
    控制台:

    四、双向认证
    1生成客户端证书

    keytool -genkey -alias client -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\Users\admin\Desktop\client.p12

    2导出客户端cer证书

    keytool -export -alias client -keystore C:\Users\admin\Desktop\client.p12 -storetype PKCS12 -keypass 123456 -file C:\Users\admin\Desktop\client.cer

    3生成keystore用来存储springboot信任的证书

    keytool -genkey -alias springboot_keystore -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\Users\admin\Desktop\springboot_keystore.keystore

    4导入客户端的公钥到springboot_keystore.keystore

    keytool -import -v -file C:\Users\admin\Desktop\client.cer -keystore C:\Users\admin\Desktop\springboot_keystore.keystore -storepass 123456

    5配置SpringBoot

    将springboot_keystore.keystore拷贝到SpringBoot项目,并添加如下配置

    #双向认证配置
    server.ssl.trust-store=classpath:springboot_keystore.keystore
    server.ssl.trust-store-password=123456
    server.ssl.client-auth=need
    server.ssl.trust-store-type=JKS
    server.ssl.trust-store-provider=SUN
    6浏览器测试

    直接访问会出现如下错误

     

    需要在电脑中安装证书

    双击client.p12,安装证书(demo是win10环境)

     

    安装成功后刷新浏览器,提示选择证书。点击“确定”。

     

    然后访问https接口,看到如下图的结果,说明配置成功。

     

    7okhttp3测试

    path:指定client.p12的路径

    如果使用单向认证的main函数继续访问,控制台打印异常信息:

    Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
    测试代码:

    package com.asyf.demo.other_api.okhttp3;

    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;

    import javax.net.ssl.*;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.security.KeyStore;
    import java.security.SecureRandom;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;

    /**
    * https双向认证
    */
    public class Test {

    //安全传输层协议
    private static final String PROTOCOL = "TLS";

    // JKS/PKCS12
    private static final String KEY_KEYSTORE_TYPE = "PKCS12";

    public static SSLSocketFactory getSocketFactory(String cerPath, String p12Path, String password) throws Exception {
    InputStream cerInputStream = null;
    InputStream p12InputStream = null;
    SSLSocketFactory socketFactory = null;
    try {
    cerInputStream = new FileInputStream(new File(cerPath));
    p12InputStream = new FileInputStream(new File(p12Path));
    KeyManager[] keyManagers = getKeyManagers(p12InputStream, password);
    TrustManager[] trustManagers = getTrustManagers(cerInputStream);
    SSLContext sslContext = getSslContext(keyManagers, trustManagers);
    socketFactory = sslContext.getSocketFactory();
    } finally {
    if (cerInputStream != null) {
    cerInputStream.close();
    }
    if (p12InputStream != null) {
    p12InputStream.close();
    }
    }
    return socketFactory;
    }

    private static SSLContext getSslContext(KeyManager[] keyManagers, TrustManager[] trustManagers) throws Exception {
    SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
    sslContext.init(keyManagers, trustManagers, new SecureRandom());
    return sslContext;
    }

    private static KeyManager[] getKeyManagers(InputStream inputStream, String password) throws Exception {
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);
    //加载证书
    keyStore.load(inputStream, password.toCharArray());
    keyManagerFactory.init(keyStore, password.toCharArray());
    KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
    return keyManagers;
    }

    private static TrustManager[] getTrustManagers(InputStream inputStream) throws Exception {
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);
    //加载证书
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    Certificate ca = certificateFactory.generateCertificate(inputStream);
    keyStore.load(null, null);
    //设置公钥
    keyStore.setCertificateEntry("server", ca);
    trustManagerFactory.init(keyStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    return trustManagers;
    }

    public static void main(String[] args) throws Exception {
    //获取SSLSocketFactory
    String certPath = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\server.cer";//服务端公钥
    String p12Path = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\client.p12";//客户端私钥
    SSLSocketFactory socketFactory = getSocketFactory(certPath, p12Path, "123456");
    //发送请求
    String url = "https://127.0.0.1:8080/demo";
    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
    clientBuilder.sslSocketFactory(socketFactory);
    //解决报错javax.net.ssl.SSLPeerUnverifiedException: Hostname 127.0.0.1 not verified
    clientBuilder.hostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String s, SSLSession sslSession) {
    System.out.println("主机:" + s);
    return true;
    }
    });
    OkHttpClient client = clientBuilder.build();

    Request.Builder builder = new Request.Builder().url(url);
    Request request = builder.build();

    Response response = client.newCall(request).execute();
    String result = response.body().string();
    //打印结果返回数据
    System.out.println(result);
    }

    }
    控制台:


    ————————————————
    版权声明:本文为CSDN博主「阿瑟与非」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/cs373616511/article/details/105628692

  • 相关阅读:
    C#中线程安全的单例模式
    分布式服务和库表设计模式详解
    通俗易懂的讲解下Java注解
    MEF框架使用总结
    Docker:四、Docker进阶 Windows Docker IIS 部署
    Docker:三、深入Docker容器&Asp.net发版
    Docker:二、开始部署第一个Asp.net应用
    Docker:一、开始部署第一个Asp.net应用
    Docker:常见命令
    .net 中的 StringBuilder 和 TextWriter 区别
  • 原文地址:https://www.cnblogs.com/telwanggs/p/16590868.html
Copyright © 2020-2023  润新知