java生成证书
添加依赖
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.69</version></dependency>
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Calendar;
import java.util.Date;/*** @Author: moses* @Date: 2023/7/4*/
public class HttpsUtil {//CN=名字与姓氏, OU=组织单位名称, O=组织名称, L=城市或区域名称, ST=省/市/自治区名称, C=双字母国家/地区代码public static final String NAME = "CN=moses, OU=glory2020.cn, O=glory2020, L=beijing, ST=beijing, C=CN";public static final String ALIAS = "king";public static final String PASSWORD = "!QAZ2wsx";public static void main(String[] args) throws Exception {GenerateNginxHttpsCertificate("ruoyi", "/Users/fanshaorong/Desktop/Program/ssl", "cert");}// yesterdaypublic static Date getStartDate() {Calendar startC = Calendar.getInstance();startC.add(Calendar.DAY_OF_YEAR, -1);Date startDate = startC.getTime();return startDate;}// one year from nowpublic static Date getEndDate() {Calendar endC = Calendar.getInstance();endC.add(Calendar.YEAR, 10);Date endDate = endC.getTime();return endDate;}public static void GenerateNginxHttpsCertificate(String hostname, String filePath, String filename) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, CertificateException, OperatorCreationException {// Generate key pairKeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");generator.initialize(4096);KeyPair keyPair = generator.generateKeyPair();// Create certificateX500Principal issuer = new X500Principal(NAME);X500Principal subject = new X500Principal(NAME);X500Name issuerName = new X500Name(issuer.getName());X500Name subjectName = new X500Name(subject.getName());// yesterdayDate startDate = getStartDate();// one year from nowDate endDate = getEndDate();X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(issuerName, new BigInteger(64, new SecureRandom()), startDate, endDate, subjectName, keyPair.getPublic());ASN1Encodable[] subjectAlternativeNames = new ASN1Encodable[]{new GeneralName(GeneralName.dNSName, hostname),// new GeneralName(GeneralName.dNSName, "www.example.com"),// new GeneralName(GeneralName.iPAddress, "192.168.0.1")};byte[] sanExtensionValue = new DERSequence(subjectAlternativeNames).getEncoded(ASN1Encoding.DER);// String dns1 = "DNS:" + hostname;Extension dns = new Extension(Extension.subjectAlternativeName, false, sanExtensionValue);builder.addExtension(dns);// 添加基本约束扩展BasicConstraints basicConstraints = new BasicConstraints(true);builder.addExtension(Extension.basicConstraints, true, basicConstraints.getEncoded());builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));// 添加Subject Key Identifier扩展builder.addExtension(Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(keyPair.getPublic()));// SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());// 添加Authority Key Identifier扩展builder.addExtension(Extension.authorityKeyIdentifier, false, new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(keyPair.getPublic()));ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());X509Certificate certificate = new JcaX509CertificateConverter().getCertificate(builder.build(signer));saveCertToFile(filePath, filename, certificate, keyPair);}public static void saveCertToFile(String filePath, String filename, X509Certificate certificate, KeyPair keyPair) throws IOException, CertificateEncodingException, NoSuchAlgorithmException, InvalidKeySpecException {// Write key pair and certificate to filesFileOutputStream keyOut = new FileOutputStream(filePath + File.separator + filename + ".private.key");keyOut.write(keyPair.getPrivate().getEncoded());keyOut.close();FileOutputStream certOut = new FileOutputStream(filePath + File.separator + filename + ".crt");certOut.write(certificate.getEncoded());certOut.close();FileOutputStream out = new FileOutputStream(filePath + File.separator + filename + ".pem");JcaPEMWriter writer = new JcaPEMWriter(new java.io.OutputStreamWriter(out));writer.writeObject(certificate);writer.close();out.close();PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyPair.getPrivate().getEncoded());KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey key = keyFactory.generatePrivate(keySpec);FileOutputStream keyout = new FileOutputStream(filePath + File.separator + filename + ".key");JcaPEMWriter keywriter = new JcaPEMWriter(new java.io.OutputStreamWriter(keyout));keywriter.writeObject(key);keywriter.close();keyout.close();try {//创建一个空的keystoreKeyStore keyStore = null;keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null, null);//将密钥对保存到keystore中char[] password = PASSWORD.toCharArray();X509Certificate[] chain = {certificate};keyStore.setKeyEntry(ALIAS, keyPair.getPrivate(), password, chain);//将keystore保存到文件try (FileOutputStream fos = new FileOutputStream(filePath + File.separator + filename + ".keystore")) {keyStore.store(fos, password);}} catch (KeyStoreException | CertificateException e) {e.printStackTrace();}}
}
复制keystore到springboot资源目录,修改application.yml配置
ssl:key-store: classpath:cert.keystorekey-store-password: '!QAZ2wsx'key-store-type: JKSenabled: true
启动项目
nginx配置
开启ssl
server {listen 443 ssl;server_name localhost;ssl_certificate /Users/fanshaorong/Desktop/Program/ssl/cert.pem;ssl_certificate_key /Users/fanshaorong/Desktop/Program/ssl/cert.key;ssl_session_cache shared:SSL:1m;ssl_session_timeout 5m;ssl_ciphers HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers on;#location / {# root html;# index index.html index.htm;#}location / {root /Users/fanshaorong/Desktop/Project/RuoYi-Vue3/ruoyi-ui;try_files $uri $uri/ /index.html;index index.html index.htm;}location ~ /test-api {proxy_ssl_certificate /Users/fanshaorong/Desktop/Program/ssl/cert.pem;proxy_ssl_certificate_key /Users/fanshaorong/Desktop/Program/ssl/cert.key;proxy_ssl_protocols TLSv1 TLSV1.1 TLSv1.2;proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;proxy_ssl_session_reuse on;proxy_redirect off;proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass https://localhost:9091;}}
server {listen 81;server_name localhost;return 301 https://$host$request_uri;#rewrite ^(.*)$ https://$host$1 permanent;
}
重启nginx -s reload
访问localhost:81将跳转到https://localhost/login?redirect=/index