JAVA通过servlet读IE端的证书即为什么老是得到null值的最终解决方案

更详细的内容参考我的另一篇:


网上交易安全之九阳神功-使用JAVA调用U盾进行客户认证的total solution


需要解决的问题:

1.Servlet如何读客户端的认证

很多网上的朋友都说

“我用X509Certificate[]certs = (X509Certificate[]) request .getAttribute("javax.servlet.request.X509Certificate");

得到的证书是个null”

几乎没有答案,这边给出解决方案

a.客户端访问这个servlet,客户端和放这个servlet的j2eeapp必须实现“双向认证”

b.J2ee app端(假设我们这边用TOMCAT实现),在实现双向认证后,其实还不够,需要加一个参数,很多人可能没注意到这个参数,下面给出方案:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"

enableLookups="false"disableUploadTimeout="true"

useURIValidationHack="false"

scheme="https"secure="true"

keystoreFile="D:/tomcat/conf/shnlap93.jks"keystorePass="xxxxxxx"

truststoreFile="D:/tomcat/conf/truststore.jks"truststorePass="aaaaaa"

truststoreType="JKS"

clientAuth="true"sslProtocol="TLS" />

看到上面那个标红的地方了吧?就是这个参数没加,因此很多人就算启用了双向认证,你的servlet在拿ie端的证书时还是会得到null值

2.好,现在客户端的公钥拿到了,怎么拿私钥?

前面说了,我们先做一个简单的,写死的,就是把客户端的私钥放在我们的网站的某个目录下,然后用程序去读出来。

因此我们的过程如下:

a.客户端通过IE输入他的交易密码

b.然后点“提交”按钮,POST到我们的这个servlet

c.Servlet先读放在网站某个目录下的该客户的私钥,loadPrivateKey后用私钥对客户提交的form里的密码进行签名。

d.Servlet获得客户端IE里的证书,把公钥拿出来,然后用公钥对签完名的byte[]进行verify, 得到true代表认签成功,false认签失败,下面是我们的servlet

此处需要注意的是我们用openssl签出的private key是不能直接被java所访问的,因为它含用:

#begin certificate

#end certificate

这样的东西,而JAVA只认#begin…#end当中的那块东西,怎么办:

使用下面这条使用把openssl签出的key转成我们java可以认的rsa的KEY

opensslpkcs8 -topk8 -inform PEM -outform DER -in shnlap93.key -out pkcs8_der.key –nocrypt

下面是我们的servlet的核心片段, 拿客户端IE的公钥,拿网站某个目录摆放的私钥,然后调用标准的JAVA电子签名

private PublicKey getPubKeyFromIE(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

System.out.println("...security receive done..." + request.getScheme());

String issue, after, before, subject;

String serialno, signalg;

int version;

String cipherSuite = "";

PublicKey pk = null;

try {

cipherSuite = (String) request

.getAttribute("javax.servlet.request.cipher_suite");

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

// response.setContentType("text/plain");

// FileInputStream fis = new FileInputStream("d://paramita.cer ");

PrintWriter out = response.getWriter();

if (cipherSuite != null) {

X509Certificate[] certs = (X509Certificate[]) request .getAttribute("javax.servlet.request.X509Certificate");

/* ibm http server us followings */

// X509Certificate[] certs = (X509Certificate[]) request

// .getAttribute("javax.net.ssl.peer_certificates");

if (certs != null) {

if (certs.length > 0) {

X509Certificate t = certs[0];

pk = t.getPublicKey();

}

} else {

if ("https".equals(request.getScheme())) {

out.println("This was an HTTPS request, "

+ "but no client certificate is available");

} else {

out.println("This was not an HTTPS request, "

+ "so no client certificate is available");

}

}

}

return pk;

} catch (Exception e) {

throw new ServletException(e);

}

}


你是一名专业的java工程师,在使用springboot结合docx4j,将InputStream流转为word文档时,并将word文档下载到客户端上。通过postman下载下来的中文名称为乱码。以下是代码 InputStream htmlStream = minioUtils.downloadFileByBucketNameAndFileName("", content.split(bucketName)[1]); // 1. 取 HTML 内容 String html = IOUtils.toString(htmlStream, StandardCharsets.UTF_8); // 2. 创建 Word 文档 WordprocessingMLPackage wordPackage = WordprocessingMLPackage.createPackage(); // 3. 导入 HTML 内容 XHTMLImporterImpl importer = new XHTMLImporterImpl(wordPackage); wordPackage.getMainDocumentPart().getContent().addAll( importer.convert(html, null) ); // 4. 保存到输出流 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Docx4J.save(wordPackage, outputStream, Docx4J.FLAG_SAVE_ZIP_FILE); // 3. 设置响应头(处理中文文件名) String fileName = contentMaster.getName() + ".docx"; String encodedFileName = URLEncoder.encode(fileName, "UTF-8") .replaceAll("\\+", "%20"); InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); return ResponseEntity.ok() .header("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName + ";" + // RFC5987 " filename=\"" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + "\"") // 传统兼容 .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(new InputStreamResource(inputStream)); 给出你的解决方案
最新发布
06-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值