java 错误:找不到或无法加载主类 原因: java.lang.ClassNotFoundException 的方法

在“系统变量”栏,“新建”,“变量名”为“CLASSPATH”,“变量值”为“.:%Java_Home%\bin;%Java_Home%\lib\tools.jar”,“确定”

在“系统变量”栏,“新建”,“变量名”为“CLASSPATH”,“变量值”为“.;%Java_Home%\bin;%Java_Home%\lib\tools.jar”,“确定”

原因:符号问题  .; ,查看是否符号路径错误

服务器上使用jar -tf ruoyi-admin-nrp.jar | grep org/bouncycastle命令发现无输出,但是在windows系统使用mvn dependency:tree时里面有[INFO] +- org.dromara:ruoyi-common-encrypt:jar:5.2.0:compile [INFO] | +- org.bouncycastle:bcprov-jdk15to18:jar:1.76:compile 最后在服务上使用jar -tf ruoyi-admin-nrp.jar发现有BOOT-INF/lib/bcprov-jdk15to18-1.76.jar 本地使用Cipher cipher = Cipher.getInstance("SM2", "BC");时正常运行,这条代码在 org.dromara:ruoyi-common-encrypt中,服务器上运行这条代码则报错java.security.NoSuchAlgorithmException: No such algorithm: SM2 我的是spring程序 工具使用时有注册 package org.dromara.common.encrypt.utils; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.engines.SM4Engine; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Base64; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.X509EncodedKeySpec; public class Sm4CBCUtils { public static final int DEFAULT_KEY_SIZE = 128; public static final String ALGORITHM_NAME = "SM4"; static { Security.addProvider(new BouncyCastleProvider()); }
最新发布
07-31
<think>我们正在处理一个关于Spring Boot应用在服务器上抛出`NoSuchAlgorithmException`,而在本地运行正常的问题。具体异常是`java.security.NoSuchAlgorithmException: No such algorithm: SM2`,发生在使用`Cipher.getInstance("SM2", "BC")`时。 根据问题描述,本地可以运行,但服务器上不行,这表明服务器环境中的Bouncy Castle库可能存在问题。 可能的原因及解决方案: 1. 服务器上的Bouncy Castle库未正确安装版本不匹配。 - 确保服务器上部署的Bouncy Castle库(bcprov-jdk15on等)与本地使用的版本一致,且位于路径中。 - 检查是否将Bouncy Castle注册为安全提供者。 2. 安全提供者注册方式问题。 - 在本地开发环境中,可能通过代码配置文件注册了Bouncy Castle,但服务器环境可能没有。 3. 服务器上的JRE安全策略限制。 - 某些服务器环境可能有严格的安全策略,限制使用非标准算法。 4. 依赖冲突。 - 服务器上可能存在多个版本的Bouncy Castle,导致冲突。 解决步骤: 步骤1:确认Bouncy Castle库已正确部署 - 检查服务器上应用的lib目录(例如,对于Spring Boot可执行jar,检查BOOT-INF/lib)是否包含Bouncy Castle的jar文件(如bcprov-jdkXX-xxx.jar)。 - 确认版本:本地和服务器使用相同版本。 步骤2:确认安全提供者已注册 - 在代码中动态注册(推荐在应用启动时注册): ```java Security.addProvider(new BouncyCastleProvider()); ``` - 者通过配置文件注册:在`java.security`文件中添加(位于`$JAVA_HOME/conf/security/java.security`): ``` security.provider.N=org.bouncycastle.jce.provider.BouncyCastleProvider ``` 其中N是下一个数字(例如,如果已有9个,则N=10)。 注意:在服务器上修改`java.security`文件可能需要权限,且可能影响其他应用。因此,更推荐在代码中动态注册。 步骤3:检查服务器上的JRE版本和安全策略 - 确认服务器JRE版本是否支持Bouncy Castle的SM2算法。SM2算法需要较新的Bouncy Castle版本(如bcprov-jdk15on 1.60及以上)。 - 检查是否存在JCE策略限制(但SM2不属于标准JCE算法,通常不受此限制,但需确保没有全局策略禁止使用Bouncy Castle)。 步骤4:检查依赖冲突 - 使用`mvn dependency:tree`(Maven)`gradle dependencies`(Gradle)检查依赖树,查看是否有其他库引入了旧版本的Bouncy Castle。 - 在服务器上,可以通过查看应用的路径来确认加载的是哪个版本的Bouncy Castle。 步骤5:在服务器上调试 - 在服务器上运行应用时,添加JVM参数以输出更多信息,例如: `-Djava.security.debug=all` - 者,在代码中输出已注册的安全提供者列表,以确认Bouncy Castle是否被正确注册: ```java Provider[] providers = Security.getProviders(); for (Provider provider : providers) { System.out.println(provider.getName()); } ``` - 同时,可以尝试输出BouncyCastleProvider是否支持"SM2"算法: ```java Provider bcProvider = Security.getProvider("BC"); if (bcProvider != null) { System.out.println("BC provider version: " + bcProvider.getVersion()); // 检查SM2算法支持 String cipherAlg = "SM2"; if (bcProvider.getService("Cipher", cipherAlg) != null) { System.out.println("SM2 is supported."); } else { System.out.println("SM2 is NOT supported."); } } else { System.out.println("BC provider is not registered."); } ``` 步骤6:考虑服务器环境的安全管理器(SecurityManager) - 如果服务器启用了SecurityManager,检查是否配置了相应的权限,允许使用Bouncy Castle。 根据上述分析,我们给出一个解决方案示例: 1. 确保依赖正确: 在pom.xml中添加Bouncy Castle依赖(使用最新版本): ```xml <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> <!-- 请检查最新版本 --> </dependency> ``` 2. 在应用启动时注册BouncyCastleProvider: 可以在Spring Boot的中静态注册: ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.Security; @SpringBootApplication public class Application { public static void main(String[] args) { Security.addProvider(new BouncyCastleProvider()); // 注册BouncyCastle SpringApplication.run(Application.class, args); } } ``` 3. 使用SM2算法时,指定提供者: ```java Cipher cipher = Cipher.getInstance("SM2", "BC"); // 确保使用"BC"作为提供者名称 ``` 4. 如果问题仍然存在,在服务器上运行依赖检查代码(步骤5中的调试代码)以获取更多信息。 注意:在服务器上部署时,确保构建过程包含了正确的依赖,并且没有打包旧版本的库。 如果以上步骤还不能解决问题,可能需要进一步检查服务器的JRE环境,例如是否使用了不同的JRE(如OpenJDK和Oracle JDK的差异)以及是否缺少相关策略文件。 最后,如果服务器是容器化环境(如Docker),确保镜像中安装了正确的JRE版本,并且应用依赖已正确复制。 相关问题: 1. 如何在Spring Boot中配置Bouncy Castle作为安全提供者? 2. 如何排查服务器环境与本地环境不一致的问题? 3. 如何解决Java中的NoSuchAlgorithmException异常?</think>### 问题分析与解决:Spring Boot服务器出现`NoSuchAlgorithmException: SM2`错误 #### 问题原因分析 1. **算法提供者未注册** Bouncy Castle(BC)未在JVM安全提供者列表中正确注册。服务器环境可能缺少动态注册配置文件修改。 2. **依赖冲突缺失** 服务器部署的JAR中可能: - 缺少Bouncy Castle依赖 - 存在版本冲突(如旧版本BC不支持SM2) - 依赖未正确打包(如`bcprov-jdk15on`未包含在`BOOT-INF/lib`) 3. **JRE环境差异** - 服务器JRE未更新策略文件(旧版JRE限制强加密算法) - 服务器使用精简版JRE(如Alpine Linux的`musl`环境缺少部分安全组件) 4. **加载器隔离** Spring Boot的加载器隔离可能导致`Cipher`无法访问BC的实现[^1]。 --- #### 解决方案 ##### 1. 显式注册Bouncy Castle提供者(代码层) 在Spring Boot启动中静态注册: ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; @SpringBootApplication public class Application { static { Security.addProvider(new BouncyCastleProvider()); // 静态注册 } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` ##### 2. 检查依赖配置 **Maven配置(确保版本≥1.68)**: ```xml <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> <!-- SM2需1.60+ --> </dependency> ``` **验证依赖打包**: ```bash # 检查服务器JAR内是否包含BC jar tf your-app.jar | grep bcprov ``` ##### 3. 服务器环境修复 - **升级JRE**:使用JDK 11+,执行: ```bash sudo apt install openjdk-17-jdk-headless ``` - **安装无限制策略文件**(旧版JDK需手动安装[JCE策略文件](https://www.oracle.com/java/technologies/javase-jce-all-downloads.html)) ##### 4. 加载器适配 显式指定加载器(适用于Spring Boot FatJAR): ```java public Cipher getSM2Cipher() throws Exception { ClassLoader originalLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); // 重置加载器 try { return Cipher.getInstance("SM2", "BC"); } finally { Thread.currentThread().setContextClassLoader(originalLoader); } } ``` ##### 5. 算法名称兼容性处理 使用标准算法名(避免大小写敏感问题): ```java Cipher cipher = Cipher.getInstance("SM2WITHSM3", "BC"); // BC规范名称 ``` --- #### 验证步骤 1. **服务器端诊断代码**: ```java @RestController public class EnvCheckController { @GetMapping("/providers") public String listProviders() { return Arrays.stream(Security.getProviders()) .map(p -> p.getName() + " v" + p.getVersion()) .collect(Collectors.joining("\n")); } } ``` 访问 `GET /providers` 确认输出包含 `BC v1.70` 2. **算法支持检查**: ```java Provider bc = Security.getProvider("BC"); System.out.println("Supports SM2: " + (bc.getService("Cipher", "SM2") != null)); // 应输出true ``` --- #### 典型错误场景修复示例 ```java // 错误用法:未指定提供者 Cipher.getInstance("SM2"); // 正确用法:显式声明BC提供者 Cipher.getInstance("SM2", "BC"); // 超安全用法:绕过加载器隔离 Cipher cipher = Cipher.getInstance( new BouncyCastleProvider().getService("Cipher", "SM2").getAlgorithm(), "BC" ); ``` --- ### 相关问题 1. 如何验证Bouncy Castle在Spring Boot中的正确注册? 2. 服务器环境与本地开发环境差异可能导致哪些加密算法问题? 3. 如何为JDK 8手动安装无限制强度加密策略文件? 4. Spring Boot的加载器隔离机制如何影响安全提供者的加载?[^1] [^1]: 加载器隔离可能导致安全提供者无法被系统API识别,需显式指定加载静态注册。 [^2]: 依赖冲突检查可通过`mvn dependency:tree`分析,确保BC库版本一致性。 [^3]: 服务器环境精简可能导致加密组件缺失,建议使用完整JRE基础镜像如`eclipse-temurin:17-jre`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值