1.jdk keytool
可以用keytool工具直接生成,需要openssl工具Binaries – OpenSSLWiki设置到环境变量里
@echo off
cd ../output
IF exist auth.jks del auth.jks
IF exist auth.key del auth.key
keytool -genkeypair -alias xxxx_key -keyalg RSA -keypass xxxxxx -keystore auth.jks -storepass xxxxxx -dname CN=xxx
keytool -list -rfc --keystore auth.jks -storepass xxxxxx | openssl x509 -inform pem -pubkey > temp.key
(@FOR /f "tokens=1* delims=:" %%a IN ('findstr /n "^" "temp.key"') DO @IF %%a leq 9 ECHO(%%b) > auth.key
del temp.key
echo Build OK!
pause
2.认证与鉴权使用
生成的authkey放到gateway下,生成的auth.jks放到auth认证服务下
网关结合鉴权,需要配置如下配置文件
spring:
security:
oauth2:
resourceserver:
jwt:
public-key-location: classpath:auth.key
认证服务配置Bean
@Bean
public JWKSource<SecurityContext> jwkSource() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JKS");
// 取得JKS文件
Resource resource = new ClassPathResource(DEFAULT_KEY_STORE_FILE);
if (!resource.exists()) {
resource = new FileSystemResource(DEFAULT_KEY_STORE_FILE);
}
try (InputStream inputStream = resource.getInputStream()) {
keyStore.load(inputStream, DEFAULT_KEY_STORE_PASSWORD.toCharArray());
RSAPublicKey publicKey = (RSAPublicKey) keyStore.getCertificate(DEFAULT_KEY_ALIAS).getPublicKey();
RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(DEFAULT_KEY_ALIAS, DEFAULT_KEY_PASSWORD.toCharArray());
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyStore(keyStore)
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
}
3.工程项目直接生成
接口AuthToolController
package xxx.authtool.controller;
import xxx.authtool.util.RsaUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.security.KeyPair;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@RestController
@RequestMapping("/generate")
public class AuthToolController {
@Value("${file-path:}")
private String filePath;
/**
* 创建并下载auth.key和auth.jks
* @param days 创建证书的有效期 单位:天 不传默认90天
* @param response http返回值
* @throws IOException 异常
*/
@GetMapping("/downloadAuthKeyZip")
public void downloadAuthKeyZip(@RequestParam(required = false) Integer days, HttpServletResponse response) throws IOException {
String dirPath = mkdir();
// 创建一个临时zip文件,用于存放要下载的多个文件
File zipFile = new File(dirPath + "/" + "authKeys.zip");
// 获取需要下载的多个文件,并将它们添加到zip文件中
List<File> filesToDownload = getFilesToDownload(dirPath, days);
addFilesToZip(filesToDownload, zipFile);
deleteFiles(filesToDownload);
//设置响应头信息
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=authKeys.zip");
// 将zip文件内容写入到HttpServletResponse输出流中,实现文件下载
try (InputStream inputStream = Files.newInputStream(zipFile.toPath());
OutputStream outputStream = response.getOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
outputStream.flush();
}
}
}
/**
* 删除文件
* @param filesToDownload 文件列表
*/
private void deleteFiles(List<File> filesToDownload) {
for (File file : filesToDownload) {
file.delete();
}
}
/**
* 获取文件列表
* @param dirPath 文件路径
* @param days 时间
* @return 文件列表
*/
private List<File> getFilesToDownload(String dirPath, Integer days) {
// 获取需要下载的多个文件
List<File> files = new ArrayList<>();
KeyPair keyPair = RsaUtil.genKeyPair();
File publicFile = RsaUtil.genPublicFile(keyPair, dirPath);
File privateFile = RsaUtil.genPrivateFile(keyPair, dirPath, days);
files.add(publicFile);
files.add(privateFile);
return files;
}
/**
* 压缩文件
* @param filesToDownload 文件列表
* @param zipFile 压缩文件
* @throws IOException 异常
*/
private void addFilesToZip(List<File> filesToDownload, File zipFile) throws IOException {
// 将多个文件压缩到zip文件中
try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) {
for (File file : filesToDownload) {
zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
try (FileInputStream inputStream = new FileInputStream(file)) {
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
zipOutputStream.write(buf, 0, len);
}
}
zipOutputStream.closeEntry();
}
}
}
/**
* 创建文件夹
* @return 文件路径
*/
private String mkdir() {
String dateString = getDateString();
// 文件夹路径
String dirPath = filePath + "/" + dateString;
File directory = new File(dirPath);
// 判断文件夹是否存在
if (!directory.exists()) {
// 创建文件夹及其父目录
directory.mkdirs();
}
return dirPath;
}
/**
* 获取日期字符串
* @return 日期字符串
*/
private String getDateString() {
Date currentDate = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
return dateFormat.format(currentDate);
}
}
RSAUtil
package xxx.authtool.util;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import sun.security.x509.X500Name;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Date;
/**
* RSA工具类
*
* @author xxx
*/
public final class RsaUtil {
public static final String DEFAULT_KEY_STORE_FILE = "auth.jks";
public static final String DEFAULT_KEY_FILE = "auth.key";
public static final String DEFAULT_KEY_STORE_PASSWORD = "xxxxxx";
public static final String DEFAULT_KEY_ALIAS = "xxxx";
public static final String DEFAULT_KEY_PASSWORD = "xxxxxx";
/**
* 随机生成密钥对
*/
public static KeyPair genKeyPair() {
try {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(2048, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
return keyPairGen.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* 生成私钥
* @param keyPair 密钥对
* @param dirPath 文件列表
* @param days 时间
* @return 秘钥文件
*/
public static File genPrivateFile(KeyPair keyPair, String dirPath, Integer days) {
File file = new File(dirPath + "/" + DEFAULT_KEY_STORE_FILE);
try (FileOutputStream fos = new FileOutputStream(file)) {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, DEFAULT_KEY_PASSWORD.toCharArray());
// 得到私钥
PrivateKey privateKey = keyPair.getPrivate();
// 为以下对象生成 2048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 90 天):
String dn = "CN=xxxx";
// 有效期默认为 90 天
int day = 90;
if (days != null) {
day = days;
}
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
new X500Name(dn).asX500Principal(),
BigInteger.valueOf(System.currentTimeMillis()),
new Date(System.currentTimeMillis()),
new Date(System.currentTimeMillis() + day * 24 * 60 * 60 * 1000L),
new X500Name(dn).asX500Principal(),
keyPair.getPublic());
ContentSigner signer =
new JcaContentSignerBuilder("SHA256withRSA").setProvider(new BouncyCastleProvider()).build(keyPair.getPrivate());
Certificate cert = new JcaX509CertificateConverter().setProvider(new BouncyCastleProvider()).getCertificate(builder.build(signer));
keyStore.setKeyEntry(DEFAULT_KEY_ALIAS, privateKey, DEFAULT_KEY_PASSWORD.toCharArray(), new Certificate[]{cert});
keyStore.store(fos, DEFAULT_KEY_STORE_PASSWORD.toCharArray());
return file;
} catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException |
OperatorCreationException e) {
throw new RuntimeException(e);
}
}
/**
* 生成公钥文件
* @param keyPair 密钥对
* @param dirPath 文件列表
* @return 公钥文件
*/
public static File genPublicFile(KeyPair keyPair, String dirPath) {
try (StringWriter sw = new StringWriter()) {
// 得到公钥
PublicKey publicKey = keyPair.getPublic();
// 获取PublicKey并将其转换为PEM格式的字符串
try (JcaPEMWriter pemWriter = new JcaPEMWriter(sw)) {
pemWriter.writeObject(publicKey);
} catch (IOException e) {
throw new RuntimeException(e);
}
File file = new File(dirPath + "/" + DEFAULT_KEY_FILE);
try (FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fw)
) {
bw.write(sw.toString());
} catch (IOException e) {
throw new RuntimeException(e);
}
return file;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
依赖
implementation 'org.bouncycastle:bcprov-jdk15on:1.69'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.69'
访问localhost:6080/generate/downloadAuthKeyZip可获取90天许可的证书
4.RSA工具类
package xxx.socket.stomp.config;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.springframework.util.Assert;
/**
* RSA工具类
*
*/
public class RsaUtils {
private static String publicKeyStr = "";
private static String privateKeyStr = "";
public static void main(String[] args) {
genKeyPair();
String password = "xxxx";
String rawPassword = encrypt(password);
String password2 = decrypt(rawPassword);
Assert.isTrue(password.equals(password2), "Error");
}
public static String encrypt(String password) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] passwordBytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
String result = new String(Base64.getEncoder().encode(passwordBytes), StandardCharsets.UTF_8);
System.out.println("Encrypt Password: " + result);
return result;
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
System.out.println("Algorithm Error\n" + e);
} catch (NoSuchPaddingException | InvalidKeyException e) {
System.out.println("Cipher Error\n" + e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
System.out.println("Password Error\n" + e);
}
return null;
}
public static String decrypt(String password) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr));
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] passwordBytes = cipher.doFinal(Base64.getDecoder().decode(password.getBytes(StandardCharsets.UTF_8)));
String result = new String(passwordBytes, StandardCharsets.UTF_8);
System.out.println("Decrypt Password: " + result);
return result;
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
System.out.println("Algorithm Error\n" + e);
} catch (NoSuchPaddingException | InvalidKeyException e) {
System.out.println("Cipher Error\n" + e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
System.out.println("Password Error\n" + e);
}
return null;
}
/**
* 随机生成密钥对
*/
public static void genKeyPair() {
try {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(2048, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
// 得到私钥
PrivateKey privateKey = keyPair.getPrivate();
// 得到公钥
PublicKey publicKey = keyPair.getPublic();
String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
System.out.println("随机生成的公钥为:" + publicKeyString);
System.out.println("随机生成的私钥为:" + privateKeyString);
publicKeyStr = publicKeyString;
privateKeyStr = privateKeyString;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
5. 参考资料
www.php1.cn/detail/Java_ShiYong_key_81410199.html
版权声明:本文为博主作者:Domerobin原创文章,版权归属原作者,如果侵权,请联系我们删除!
原文链接:https://blog.csdn.net/weixin_40240897/article/details/130241979