Java 11 调用SunPKCS11读取USB令牌私钥提示类无法访问错误如何解决
问题根因
绝大多数情况下该报错是Java 9及更高版本的内部API权限调整导致的:sun.security.pkcs11.SunPKCS11类中接收配置路径/Config对象的构造方法被改为包私有属性,不允许外部包直接调用实例化。
如果是Java 8及更低版本出现该报错,需检查当前JDK是否为标准OpenJDK/OracleJDK,非标准发行版可能会修改SunPKCS11类的访问权限。
解决方案
方案1:使用官方推荐的标准API实例化(推荐)
Java 9+官方提供了公开的配置初始化方式,无需直接调用SunPKCS11的构造方法,代码示例如下:
import java.security.Provider; import java.security.Security; // 1. 获取预置的SunPKCS11 Provider基础实例 Provider pkcs11Provider = Security.getProvider("SunPKCS11"); // 2. 传入配置文件路径完成初始化配置 pkcs11Provider = pkcs11Provider.configure(tmpConfigFile.getAbsolutePath()); // 3. 将配置完成的Provider添加到Security上下文即可正常使用 Security.addProvider(pkcs11Provider);
该方案兼容所有Java 9及更高版本,不依赖内部API,后续版本升级不会出现兼容性问题。
方案2:调整JVM模块导出参数(临时兼容用,不推荐)
如果需要保留原有new SunPKCS11()的写法,可在JVM启动参数中添加如下配置,放开内部包访问限制:
--add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED
该方案属于强制突破内部API访问限制,仅建议临时调试使用,后续JDK版本可能移除相关API导致代码失效。
注意事项
- 调用
configure方法前不要将未配置的SunPKCS11基础实例加入Security的Provider列表,必须配置完成后再添加 - 配置文件中必须正确指定
library参数,值为USB令牌对应的PKCS11驱动文件(Windows为.dll、Linux为.so、MacOS为.dylib)的绝对路径
内容的提问来源于stack exchange,提问作者Lê Thanh Tùng
相关产品推荐
相关产品推荐

