一、应用(微服务)级别解决方案

1、jdk生成证书

使用jdk自带的keytools生成keystore

-- 打开cmd命令窗口,切换路径到jdk/bin下面
C:\Program Files\Java\jdk1.8.0_60\bin>.\keytool.exe -genkeypair -alias mall-alias -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -keystore E:\git_source\mall\zlb-mall-application\cer\mall-alias.keystore -storepass 123456 -ext san=dns:localhost

执行情况如下: 

 在目录下可以看见当前生成的证书。

 2、查看证书

 .\keytool.exe -list -v -keystore E:\git_source\mall\zlb-mall-application\cer\mall-alias.keystore

执行情况如下: 

 

 查看密钥详情信息:

 .\keytool.exe -list -rfc -keystore E:\git_source\mall\zlb-mall-application\cer\mall-alias.keystore

执行情况如下: 

 3、导出证书

C:\Program Files\Java\jdk1.8.0_60\bin>.\keytool.exe -exportcert -alias mall-alias -keystore E:\git_source\mall\zlb-mall-application\cer\mall-alias.keystore -file e:\git_source\mall\zlb-mall-application\cer\my.cer

导出证书完成 

 查看本地路径文件

 4、代码验证证书可用性

首先用代码解析证书中的公私钥

	/**
	 * 从KeyStore中获取公钥,并经BASE64编码
	 *
	 * @param keyStorePath
	 * @param alias
	 * @param storePass
	 * @author 蚂蚁兄弟
	 */
	public static String getStrPublicKey(String keyStorePath, String alias, String storePass) throws Exception {

		PublicKey key = getPublicKey(keyStorePath, alias, storePass);

		String strKey = encryptBASE64(key.getEncoded());

		return strKey;

	}
	
	/**
	 * 获取经BASE64编码后的私钥
	 *
	 * @param keyStorePath
	 * @param alias
	 * @param storePass
	 * @param keyPass
	 * @return
	 * @throws Exception
	 * @author 蚂蚁兄弟
	 */

	public static String getStrPrivateKey(String keyStorePath, String alias, String storePass, String keyPass) throws Exception {

		PrivateKey key = getPrivateKey(keyStorePath, alias, storePass, keyPass);

		String strKey = encryptBASE64(key.getEncoded());

		return strKey;

	}
	
	public static void main(String[] args) throws Exception {

		String keyStorePath = "E:\\git_source\\mall\\zlb-mall-application\\cer\\mall-alias.keystore";

		String strPublicKey = getStrPublicKey(keyStorePath, "mall-alias", "123456");
		System.out.println("公钥:"+strPublicKey);

		String strPrivateKey = getStrPrivateKey(keyStorePath, "mall-alias", "123456", "123456");
		System.out.println("私钥:"+strPrivateKey);
		
		//公钥:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYHpqAxxsgmzKP7V8Lw4gRMmzQvExyuZNuqzxou8+SPWSjlU1VrYaa07Wt/l39pEpq97B/kUI1Te6Uy09+BmhxyJ6SkDslAtCJcQDa/zfvJb4xU6m+QwtBh7DhIeFequJWRJMnOxipgF10g6jd3QNJ6/UBjGwF2gUYafaJZu+lfQIDAQAB
		//私钥:MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJgemoDHGyCbMo/tXwvDiBEybNC8THK5k26rPGi7z5I9ZKOVTVWthprTta3+Xf2kSmr3sH+RQjVN7pTLT34GaHHInpKQOyUC0IlxANr/N+8lvjFTqb5DC0GHsOEh4V6q4lZEkyc7GKmAXXSDqN3dA0nr9QGMbAXaBRhp9olm76V9AgMBAAECgYBBF/dtW8YT8dV1GVIuqoEzOqyttaXRAfBAzy2Oc6+jGHpUNbNeEl8jKaz4w3xc6Uye8Vapf/Mg9DQ/n7BocT2HqjgdKve71h60lw9mgSHM9Ykjbpd1Gfk9oQrLhow8eolo+dYu/98f7ho2iBXnQJ5VjOzg8957U4UDScWqGNaEAQJBAMcfxyBwjHPjQzU/fooa1G1Df1VE94AXSfm5jHPGRvbZOgeHJGsXgcGmlysVf5ycP2tE7/n89nPCGX0FdeuIKUECQQDDkcmejsKkX7idpko7azBXzrSNWzZojzEdyoXaLjLFeNkF4cGwb94fF4Lz5wckfcT8mCKB+J2tKzxtIkMAIJE9AkACSnlOBD15b9nsGOjpydk70JT8dCiszpfJSbs18cgLOwCR6ZofqUuS4MnIcxzevmV0ZHymUaS8PDVy3Mc4iH6BAkEAosbxXbvNXisd6nnCR3qMHkm6Ff3ZZ2Xnp7gteNADCkHvwOmK4WP7KT3UjVW5qDHWh7fI4Q0hkETwYpWl1rFEsQJBAJpEmUOzCqtHDQjvsXVYVT93dyhZNtNZISenJ8qFSKSDlvUmrxU6xX66tU5vX3ExSueXZ89zKCKbMm/muOCl7Iw=
	}
	

然后用代码验证公私钥的可用性

    public static void main(String[] args) throws Exception {
        //生成公钥和私钥
        Map<String, String> keyMap = new HashMap<>();
        keyMap.put("publicKey", "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYHpqAxxsgmzKP7V8Lw4gRMmzQvExyuZNuqzxou8+SPWSjlU1VrYaa07Wt/l39pEpq97B/kUI1Te6Uy09+BmhxyJ6SkDslAtCJcQDa/zfvJb4xU6m+QwtBh7DhIeFequJWRJMnOxipgF10g6jd3QNJ6/UBjGwF2gUYafaJZu+lfQIDAQAB");
        keyMap.put("privateKey", "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJgemoDHGyCbMo/tXwvDiBEybNC8THK5k26rPGi7z5I9ZKOVTVWthprTta3+Xf2kSmr3sH+RQjVN7pTLT34GaHHInpKQOyUC0IlxANr/N+8lvjFTqb5DC0GHsOEh4V6q4lZEkyc7GKmAXXSDqN3dA0nr9QGMbAXaBRhp9olm76V9AgMBAAECgYBBF/dtW8YT8dV1GVIuqoEzOqyttaXRAfBAzy2Oc6+jGHpUNbNeEl8jKaz4w3xc6Uye8Vapf/Mg9DQ/n7BocT2HqjgdKve71h60lw9mgSHM9Ykjbpd1Gfk9oQrLhow8eolo+dYu/98f7ho2iBXnQJ5VjOzg8957U4UDScWqGNaEAQJBAMcfxyBwjHPjQzU/fooa1G1Df1VE94AXSfm5jHPGRvbZOgeHJGsXgcGmlysVf5ycP2tE7/n89nPCGX0FdeuIKUECQQDDkcmejsKkX7idpko7azBXzrSNWzZojzEdyoXaLjLFeNkF4cGwb94fF4Lz5wckfcT8mCKB+J2tKzxtIkMAIJE9AkACSnlOBD15b9nsGOjpydk70JT8dCiszpfJSbs18cgLOwCR6ZofqUuS4MnIcxzevmV0ZHymUaS8PDVy3Mc4iH6BAkEAosbxXbvNXisd6nnCR3qMHkm6Ff3ZZ2Xnp7gteNADCkHvwOmK4WP7KT3UjVW5qDHWh7fI4Q0hkETwYpWl1rFEsQJBAJpEmUOzCqtHDQjvsXVYVT93dyhZNtNZISenJ8qFSKSDlvUmrxU6xX66tU5vX3ExSueXZ89zKCKbMm/muOCl7Iw=");

        String publicKey = keyMap.get("publicKey");
        String privateKey = keyMap.get("privateKey");
        System.out.println("公钥:"+publicKey);
        System.out.println("私钥:"+privateKey);
        // 原始字符串
        String message = "测试公钥加密私钥解密 原始内容";
        System.out.println("原始数据:"+message);

        String messageEn = publicKeyEncrypt(message, publicKey);
        System.out.println("公钥加密后内容:" + messageEn);
        String messageDe = privateKeyDecrypt(messageEn, privateKey);
        System.out.println("私钥解密后内容:" + messageDe);

        System.out.println("===============================");

        message = "测试私钥加密公钥解密 原始内容";
        System.out.println("原始数据:"+message);
        String messageEn1 = privateKeyEncrypt(message, privateKey);
        System.out.println("私钥加密后内容:" + messageEn1);
        String messageDe1 = publicKeyDecrypt(messageEn1, publicKey);
        System.out.println("公钥解密后内容:" + messageDe1);
    }
  
   /**
     * RSA公钥加密
     *
     * @param str       加密字符串
     * @param publicKey 公钥
     * @return 密文
     * @throws Exception 加密过程中的异常信息
     * @author 蚂蚁兄弟
     */
    public static String publicKeyEncrypt(String str, String publicKey) throws Exception {
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").
                generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }
    
    /**
     * RSA私钥解密
     *
     * @param str        加密字符串
     * @param privateKey 私钥
     * @return 铭文
     * @throws Exception 解密过程中的异常信息
     * @author 蚂蚁兄弟
     */
    public static String privateKeyDecrypt(String str, String privateKey) throws Exception {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA")
                .generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }
    
    /**
     * RSA私钥加密
     *
     * @param str
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static String privateKeyEncrypt(String str, String privateKey) throws Exception {
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        PrivateKey priKey = KeyFactory.getInstance("RSA").
                generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, priKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes()));
        return outStr;
    }

    /**
     * RSA公钥解密
     *
     * @param str
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String publicKeyDecrypt(String str, String publicKey) throws Exception {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        PublicKey pubKey =  KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

5、配置证书到springboot项目

首先将刚刚生成的证书文件放到项目resources目录下,然后在application.yml中配置如下信息。

server:
  ssl:
    key-store: classpath:mall-alias.keystore
    key-store-type: JKS
    key-alias: mall-alias
    key-store-password: 123456
    key-password: 123456

此时在浏览器访问:https协议时,提示如下信息。说明证书配置完成。

 6、安装证书

双击my.cer安装证书。

  安装完成证书后,再次访问,就不会出现“不安全”的提示了。

二、网络负载级别解决方案

1、安装openSSL,执行如下命令

PS E:\git_source\mall\zlb-mall-application\cer\nginx> openssl genrsa -des3 -out mall.key 1024
Loading 'screen' into random state - done
Generating RSA private key, 1024 bit long modulus
..................++++++
....++++++
e is 65537 (0x10001)
Enter pass phrase for mall.key:
Verifying - Enter pass phrase for mall.key:

PS E:\git_source\mall\zlb-mall-application\cer\nginx> openssl req -new -key mall.key -out mall.csr
Enter pass phrase for mall.key:
Loading 'screen' into random state - done
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:bj
Locality Name (eg, city) []:bj
Organization Name (eg, company) [Internet Widgits Pty Ltd]:hw
Organizational Unit Name (eg, section) []:zg
Common Name (e.g. server FQDN or YOUR name) []:cpf.com
Email Address []:422121212@qq.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:


PS E:\git_source\mall\zlb-mall-application\cer\nginx> openssl rsa -in .\mall.key.src -out mall.key
Enter pass phrase for .\mall.key.src:
writing RSA key
PS E:\git_source\mall\zlb-mall-application\cer\nginx> openssl x509 -req -days 365 -in .\mall.csr -signkey .\mall.key -out mall.crt
Loading 'screen' into random state - done
Signature ok
subject=/C=cn/ST=bj/L=bj/O=msb/OU=msb/CN=cpf.com/emailAddress=asdasdf@qq.com
Getting Private key
PS E:\cer2\nginx>

2、配置nginx.conf

主要是如下两处,一般企业都是通过CA授权方购买证书,配置上证书信息即可。

        ssl_certificate      E://git_source//mall//zlb-mall-application//cer//nginx//dongbao.crt;
        ssl_certificate_key  E://git_source//mall//zlb-mall-application//cer//nginx//dongbao.key;

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
	
	
	upstream com.cpf {
		server 127.0.0.1:8080; # 需要监听的端口名 我用的
		keepalive 64;
	}

    # HTTPS server
    #
    server {
        listen       443 ssl;
        server_name  cpf.com;
		

        ssl_certificate      E://git_source//mall//zlb-mall-application//cer//nginx//dongbao.crt;
        ssl_certificate_key  E://git_source//mall//zlb-mall-application//cer//nginx//dongbao.key;
		

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        location / {
            proxy_pass http://com.cpf;
        }
    }
	

}

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐