使用java applet通过签名访问客户端串口

前端时间公司有需求要访问客户端串口读取电子称的数据,通过网上资料,决定使用applet通过电子签名的形式实现。

1.先写applet:这里我是使用RXRTcomm.jar

LocalFileApplet.java,JobThread.java

public class LocalFileApplet extends Applet {
    private static final String LIB_PATH_SUFFIX = "system32";
    private static final String DLL_FILE = "rxtxSerial.dll";
    private String msg = "";
    private boolean ready;
    private boolean right=true;
    private String commName;
    CommPortIdentifier portId ;
    SerialPort serialPort;
    InputStream is;
    public boolean isRight() {
        return right;
    }
    public void setRight(boolean right) {
        this.right = right;
    }
    public CommPortIdentifier getPortId() {
        return portId;
    }
    public void setPortId(CommPortIdentifier portId) {
        this.portId = portId;
    }
    public SerialPort getSerialPort() {
        return serialPort;
    }
    public void setSerialPort(SerialPort serialPort) {
        this.serialPort = serialPort;
    }
    public InputStream getIs() {
        return is;
    }
    public void setIs(InputStream is) {
        this.is = is;
    }
    public boolean isReady() {
        return ready;
    }
    public void setReady(boolean ready) {
        this.ready = ready;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getCommName() {
        return commName;
    }
    public void setCommName(String commName) {
        this.commName = commName;
    }
    static{
        //System.setSecurityManager(null);
        System.setSecurityManager(null);
        String drivername = "gnu.io.RXTXCommDriver";
        try {
            CommDriver driver = (CommDriver) Class.forName(drivername).newInstance();
            driver.initialize();
        } catch (InstantiationException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (ClassNotFoundException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
    
    public void paint(Graphics g ){
        //showPorts(g);
    }
    public void initPort() throws NoSuchPortException {
                CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(commName);
                if (!portId.isCurrentlyOwned()) {
                    SerialPort port;
                    try {
                        port = (SerialPort) portId
                                .open("SerialMain", 50);
                        port.setSerialPortParams(9600, SerialPort.DATABITS_8,
                                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                        port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
                         is = port.getInputStream();
                         System.out.println("得到inputstream");
                    } catch (PortInUseException e) {
                        // TODO Auto-generated catch block
                        cleanPort();
                        e.printStackTrace();
                    } catch (UnsupportedCommOperationException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    
                }
            }
 
  public void cleanPort(){
        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        serialPort.close();
    }
    public void init(){
        //listPorts();
        System.out.println("1212");
        x();
        this.setBounds(0,0,0,0);
        this.repaint();
    }
    
    public void start(){
        try {
            initPort();
        } catch (NoSuchPortException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            this.setRight(false);
        }
        JobThread job = new JobThread(this);
        Thread t = new Thread(job);
        t.start();
    }
    public void stop(){
        cleanPort();
    }
    private void showPorts(Graphics g ){
        g.drawString("扫描本地计算机上的串口:!",10,10);
        String[] ports = listPorts().split(",");
        if(ports.length==0){
            g.drawString("本地计算机上没有发现串口:!",10,30);
        }else{
            int y = 50;
            g.drawString("本地计算机上发现"+ports.length+"个串口:!",10,30);
            for (int i = 0; i < ports.length; i++) {
                String port = (String) ports[i];
                g.drawString(port,10,y);
                y += 20;
            }
        }
    }
    public String listPorts(){
        String commName="";
        Enumeration en = CommPortIdentifier.getPortIdentifiers();
        CommPortIdentifier portId;
        while (en.hasMoreElements()) {
            portId = (CommPortIdentifier) en.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL){
                if(commName==""){
                    commName+=portId.getName();
                }else{
                    commName+=","+portId.getName();
                }
            }
        }
        return commName;
    }
    private void downDll(){

        try {
            // 获取加载库时搜索的路径列表
            String dirs = System.getProperty("java.library.path");
            String[] libs = dirs.split(";");
            String libPath = "";
            for (String lib : libs) {
                if (lib.toLowerCase().endsWith(LIB_PATH_SUFFIX)) {
                    libPath = lib;
                    break;
                }
            }
            File dll = new File(libPath, DLL_FILE);
            if (!dll.exists()) {
                URL url = new URL(super.getCodeBase() + DLL_FILE);
                InputStream is = url.openConnection().getInputStream();
                FileOutputStream fos = new FileOutputStream(dll);
                byte[] buf = new byte[256]; // 读取缓存
                int len = 0;
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
                fos.flush();
                fos.close();
                is.close();
                System.out.println("创建文件完成[" + dll + "].");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }
    public void x() {
        try {
            // 获取加载库时搜索的路径列表
            String dirs = System.getProperty("java.library.path");
            String[] libs = dirs.split(";");
            String libPath = "";
            for (String lib : libs) {
                if (lib.toLowerCase().endsWith(LIB_PATH_SUFFIX)) {
                    libPath = lib;
                    break;
                }
            }
            File dll = new File(libPath, DLL_FILE);
            if (!dll.exists()) {
                URL url = new URL(super.getCodeBase() + DLL_FILE);
                InputStream is = url.openConnection().getInputStream();
                FileOutputStream fos = new FileOutputStream(dll);
                byte[] buf = new byte[256]; // 读取缓存
                int len = 0;
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
                fos.flush();
                fos.close();
                is.close();
                System.out.println("创建文件完成[" + dll + "].");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            System.loadLibrary("rxtxSerial");
        }
    }
}
public class JobThread implements Runnable{
    private LocalFileApplet applet;
    public JobThread(LocalFileApplet applet) {
        this.applet = applet;
    }
    public void run() {
        InputStream is = applet.getIs();
        try {
            while(true){
                String msg="";
                byte[] str = new byte[1024];
                System.out.println("准备接收数据");
                is.read(str);
                System.out.println("收到数据" + new String(str));

                String txt[] = new String[3];
                String value = new String(str);
                if (value != null) {
                    String vxxx[] = value.split(",");
                    if (vxxx.length > 1) {
                        String[] a = value.split(",")[1].split(" ");

                        int i = 0;
                        for (String v : a) {
                            if (v.length() > 0) {
                                txt[i] = v;
                                i++;
                            }
                        }
                        if (txt[0].length() == 1) {
                            msg = txt[1].substring(0,
                                    txt[1].length() - 2)
                                    + "."
                                    + txt[1].substring(txt[1].length() - 2,
                                            txt[1].length());
                        } else {
                            msg = txt[1].substring(0,
                                    txt[1].length() - 3)
                                    + "."
                                    + txt[1].substring(txt[1].length() - 3,
                                            txt[1].length());
                        }
                    }
                    if(msg==""||applet.getMsg().equals(msg)){
                        applet.setMsg(msg);
                        applet.setReady(false);
                        System.out.println(msg);
                        applet.repaint();
                    }else{
                        applet.setMsg(msg);
                        applet.setReady(true);
                        System.out.println(msg);
                        applet.repaint();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();  
        }
    }
}   

然后用eclipse打包,到这里都很顺利,然后签名的时候遇到了很多问题。

正确的方法是:

服务器端:

1.为刚才创建的包文件(LocalFileApplet.jar)创建keystore和keys。

keytool -genkey -keystore LocalFileApplet.keystore –alias LocalFileApplet -keyalg DSA 

2.用LocalFileApplet.keystore 对签名LocalFileApplet.jar

jarsigner -keystore LocalFileApplet.keystore LocalFileApplet.jar LocalFileApplet

3.生产LocalFileApplet.cer(这个是客户端需要的秘钥)

keytool -export -keystore LocalFileApplet.keystore -alias LocalFileApplet-file LocalFileApplet.cer 

客户端:

1.找到jre(1.7以上版本,1.6没有例外站点)把LocalFileApplet.cer导入到cacerts

路径:***\jre1.8.0_45\lib\security

keytool -import -alias LocalFileApplet -file LocalFileApplet.cer -keystore cacerts 

2.修改策略文件java.plicy

添加keystore "file:/C:/Program Files (x86)/Java/jre1.8.0_45/lib/security/cacerts", "JKS";

在grant下面增加

permission java.lang.RuntimePermission "loadLibrary.rxtxSerial", "read";
permission java.util.PropertyPermission "java.library.path", "read";
permission java.util.PropertyPermission "java.library.path", "write";
permission java.io.FilePermission "C:/Windows/system32/rxtxSerial.dll", "read";
permission java.io.FilePermission "C:/Windows/system32/rxtxSerial.dll", "write";
permission java.io.FilePermission "C:/Program Files (x86)/Java/jre1.8.0_45/lib/ext/amd64/rxtxSerial.dll", "read";
permission java.io.FilePermission "C:/Program Files (x86)/Java/jre1.8.0_45/lib/ext/amd64/rxtxSerial.dll", "write";
permission java.util.PropertyPermission "gnu.io.rxtx.SerialPorts","read";
permission java.lang.RuntimePermission "setSecurityManager";

3.把rxtxSerial.dll放到C:\Windows\System32下

4.配置本地java,打开:控制面板\程序\java 安全 例外站点
把服务器网站输入例如:http://localhost:8080/demo/

注:以/结尾,否则无效

5.高级:JNLP 文件/MIME 关联 选为始终允许,
安全执行环境勾选 允许用户为签名的内容授予权限 允许用户解释JNLP安全请求
混合代码 (沙箱代码与可信代码) 安全验证 选 启动-隐藏警告并在保护下运行
对以下项执行已签名代码证书撤销检查 选 不检查
对以下项执行 TLS 证书撤销检查 选 不检查

 

 

 

 

然后在html中调用applet

index.html

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<script type="text/javascript">
var t;
function startComm(){
    document.applets["myapp"].start();
        process();
}
function process(){
    var ready = document.applets["myapp"].isready();
        if(ready){
                 // document.applets["myapp"].setReady(false);
                  var msg = document.applets["myapp"].getMsg();
                  document.getElementById("t").value=msg;
        } 
        t=setTimeout(process(),35);
    }
function showComm(){
     var commName = document.applets["myapp"].listPorts();
     var html=""; //<option value ="">Volvo</option>  
     var names=commName.split(",");
     for(var i=0;i<names.length;i++){
         html+=" <option value =‘"+names[i]+"‘>"+names[i]+"</option>"
     }
     document.getElementById("commNum").innerHTML=html;
     
     document.applets["myapp"].setCommName(names[0]);
}
function changeComm(){
     var commName =document.getElementById("commNum").value();
     document.applets["myapp"].setCommName(commName);
}
function closeComm(){
     clearTimeout(t);
}
</script>
<body onload="showComm()">
<!--"CONVERTED_APPLET"-->
<!-- HTML CONVERTER -->
<APPLET CODEBASE="." CODE="com.LocalFileApplet.class" ARCHIVE="LocalFileApplet.jar,RXTXcomm.jar" WIDTH="200" HEIGHT="100" name="myapp"> </APPLET> 
<!--
"END_CONVERTED_APPLET"-->
<input type=
"button" value="确定" id="x" onclick="startComm()">
<input type=
"button" value="关闭" id="s" onclick="closeComm()">
<input id=
"t" type="text" value="" >
<
select id="commNum" onkeyup="showComm()" onchange="changeComm()">
</
select>
</body>
</html>

很奇怪,这样写不能读,最后我无奈了,就不打包,直接引用com.LocalFileApplet.class,可以了

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title></title>
</head>
<script type="text/javascript">
var t;
function startComm(){
    document.applets["myapp"].start();
        process();
}
function process(){
    var ready = document.applets["myapp"].isready();
        if(ready){
                 // document.applets["myapp"].setReady(false);
                  var msg = document.applets["myapp"].getMsg();
                  document.getElementById("t").value=msg;
        } 
        t=setTimeout(process(),35);
    }
function showComm(){
     var commName = document.applets["myapp"].listPorts();
     var html=""; //<option value ="">Volvo</option>  
     var names=commName.split(",");
     for(var i=0;i<names.length;i++){
         html+=" <option value =‘"+names[i]+"‘>"+names[i]+"</option>"
     }
     document.getElementById("commNum").innerHTML=html;
     
     document.applets["myapp"].setCommName(names[0]);
}
function changeComm(){
     var commName =document.getElementById("commNum").value();
     document.applets["myapp"].setCommName(commName);
}
function closeComm(){
     clearTimeout(t);
}
</script>
<body onload="showComm()">
<!--"CONVERTED_APPLET"-->
<!-- HTML CONVERTER -->
<APPLET CODEBASE="." CODE="com.LocalFileApplet.class" ARCHIVE="RXTXcomm.jar" WIDTH="200" HEIGHT="100" name="myapp">   
 </APPLET> 
<!--"END_CONVERTED_APPLET"-->
<input type="button" value="确定" id="x" onclick="startComm()">
<input type="button" value="关闭" id="s" onclick="closeComm()">
<input id="t" type="text" value="" >
<select id="commNum" onkeyup="showComm()" onchange="changeComm()">  
</select> 
</body>
</html>

难道是LocalFileApplet.jar签名出问题了?

但是RXTXcomm.jar同样签名的,为什么RXTXcomm.jar签名有效,LocalFileApplet.jar签名无效

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。