I am working on some new functionality for one of our existing Java based web applications. The web app itself is hosted on one of our internal servers and can be accessed via the browser at several computer terminals throughout our facility. The application is for conducting quality checks at various stages of our production process. Currently, users are required to manually login by selecting their userName from a drop down and entering their password before conducting each quality check. In order to speed up the process, I have been asked to implement the reading of a smart card for login.
I have written a utility class using javax.smartcardio and I am able to access the USB card reader terminal plugged into my laptop, read the ATR from the card and use the info to login to the application when I am running the application on my local tomcat7 server. So, on my local machine, everything works great.
Unfortunately, once I deploy the application to our web server, I can no longer detect the card reader terminal as I believe that the Java web application is actually looking for the reader on the machine that it is deployed to.
Is there any way that I can have my java code access a card reader plugged into a remote work station through interaction with the browser?
The web app is written in GWT, and I am using RPC calls to access the back end server side code. Any help is greatly appreciated. The card reader code is quite simple, so I'll post it if that helps:
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;
public class SwipeCardUtil
{
private static org.apache.log4j.Logger LOGGER = org.apache.log4j.Logger.getLogger("hwslqc");
/**
* @return ATR
*/
public static String readCardATR()
{
String ATR = "";
try
{
// Show the list of available terminals
TerminalFactory factory = TerminalFactory.getDefault();
List terminals = factory.terminals().list();
if (terminals.size() == 0)
{
LOGGER.error("No Swipe Card Terminals Found");
return null;
}
//System.out.println("Terminal: " + terminals.get(0).getName());
// Get the first terminal in the list
CardTerminal terminal = terminals.get(0);
if(terminal.isCardPresent())
{
// Establish a connection with the card using
// "T=0", "T=1", "T=CL" or "*"
Card theCard = terminal.connect("*");
// Get ATR
byte[] baATR = theCard.getATR().getBytes();
ATR = SwipeCardUtil.byteArrayToHexString(baATR);
//System.out.println("ATR: " + ATR);
// Disconnect
// true: reset the card after disconnecting card.
theCard.disconnect(true);
}
else{
return null;
}
}
catch (Exception ex) {
LOGGER.error("No Card Reader Connected. Please connect a Card Reader and try again. "+ex.toString());
ex.printStackTrace();
}
return ATR;
}
/**
* @param theBytes
* @return theByteArray as a hex string
*/
public static String byteArrayToHexString(byte[] theBytes)
{
StringBuffer sb = new StringBuffer(theBytes.length * 2);
for (int i = 0; i < theBytes.length; i++)
{
int byteToRead = theBytes[i] & 0xff;
if (byteToRead < 16)
{
sb.append('0');
}
sb.append(Integer.toHexString(byteToRead));
}
return sb.toString().toUpperCase();
}
}
解决方案
Your client is a web browser, and your web app is deployed on a remote server. The only way to get the reader's data from the client is to implement a piece of software running on the client side.
There are several ways to do this but many will not run on the client's web browser.
You can try to implement an applet, but chances are high that the applet will not have sufficient rights to access the client's hardware. To elevate the applets privileges it must be signed by a browser trusted CA. That's quite an endeavour.
Another way would be to not use a web browser at all but to implement a rich client software. But that is as much pain as the previous suggestion since the whole productbis based on a thin client/web browser concept.
Maybe you could use a single sign on approach. If the users are on a windows machine and logged on with their account, you could use waffle.