您的位置:首页 > 编程语言 > Java开发

java程序设计中密码屏蔽(awt/swing/command line)

2004-08-02 22:06 621 查看
在网上关于JAVA下密码屏蔽输入的文章比较多了,但是都不是多全面和详细,今天在http://java.sun.com上看到了此文章,打算把它翻译出来。因为经验不够,可能翻译的还有出入。

本篇文章(指原文)第一次发表于2002年9月。在JAVA下,利用AWT/SWING对用户输入密码进行屏蔽是很方便的,但是缺少I/O API,因此在命令行下来实现像UNIX的PASSWORD shadow就不容易了。本文就利用AWT/SWING/COMMAND LINE三种情况都一一作了较详细的介绍。

Password Masking in AWT
---------------------------------
如果提供图形界面登录对话框,可以利用AWT组件库中定义的TextField对象,该对象的定义继承结构如下:

java.lang.Object
|
+--java.awt.Component
|
+--java.awt.TextComponent
|
+--java.awt.TextField

在该对象中,定义了用于设置和维护用户输入字符回显方式的方法,这些方法的定义形式为:
char getEchoChar():获取用户定义的文本区回显字符;
boolean echoCharIsSet()判断是否定义了回显字符;
void setEchoChar(char c):设置文本区回显字符为字符。
具体代码为:
TextField password = new TextField(8);
password.setEchoChar('*');
其中8为文本输入的最大字符数,如果为0的话,则密码不会被屏蔽。

Password Masking in Swing
---------------------------------
利用JSWING组件,可以用JPasswordField对象,它的继承结构为:
java.lang.Object
|
+--java.awt.Component
|
+--java.awt.Container
|
+--javax.swing.JComponent
|
+--javax.swing.text.JTextComponent
|
+--javax.swing.JTextField
|
+--javax.swing.JPasswordField

具体代码为:
JPasswordField password = new JPasswordField(8);
password.setEchoChar('#');

Command-Line Input Masking
----------------------------------
不像Awt/Swing,在Java中没有专门用于屏蔽命令行下文本输入的API.如果想提供基于命令行文本输入的JAVA应用程序,一种方法是用Java Native Interface(JNI),但是对于一不太熟悉C/C++的开发者,或者坚持要用100%纯JAVA的开发者是难了一些。

这里提供针对此问题一个解决方案,较早的写关于此问题的文章,是像UNIX一样,用一个独立的线程来屏蔽(擦除)回显的字符。这篇文章,现在可以在http://forum.java.sun.com/thread.jsp?forum=9&thread=490728看到。

简单的解决方法
================
用一个独立的线程,在字符输入时擦除回显的字符,并用星号(*)来替换。代码如下:

//EraserThread.java

import java.io.*;

class EraserThread implements Runnable {
private boolean stop;

/**
*@param The prompt displayed to the user
*/
public EraserThread(String prompt) {
System.out.print(prompt);
}

/**
* Begin masking...display asterisks (*)
*/
public void run () {
stop = true;
while (stop) {
System.out.print("/010*");
try {
Thread.currentThread().sleep(1);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
}

/**
* Instruct the thread to stop masking
*/
public void stopMasking() {
this.stop = false;
}
}

(注:本方法运行运行大量线程,如果电脑承担较大的负荷,系统就不会保证线程运行的稳定性。)

下边的PasswordField类利用EraserThread类,用于用(*)来替换用户输入的密码字符.

//PasswordField.java

public class PasswordField {

/**
*@param prompt The prompt to display to the user
*@return The password as entered by the user
*/
public static String readPassword (String prompt) {
EraserThread et = new EraserThread(prompt);
Thread mask = new Thread(et);
mask.start();

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String password = "";

try {
password = in.readLine();
} catch (IOException ioe) {
ioe.printStackTrace();
}
// stop masking
et.stopMasking();
// return the password entered by the user
return password;
}
}

TestApp.java是对此方法的一个应用.

//TestApp.java

class TestApp {
public static void main(String argv[]) {
String password = PasswordField.readPassword("Enter password: ");
System.out.println("The password entered is: "+password);
}
}

让代码更安全和可靠
=======================
1.声明private volatile boolean stop;volatile关键字用于指定和进程同步进行,换句话说就是变量的值直接从内存中讲习取,不在堆栈中留有拷贝。
2.为了保证在担有重负荷的机器上稳定运行,设置线程的优先权更高。

//MaskingThread.java

import java.io.*;

/**
* This class attempts to erase characters echoed to the console.
*/

class MaskingThread extends Thread {
private volatile boolean stop;
private char echochar = '*';

/**
*@param prompt The prompt displayed to the user
*/
public MaskingThread(String prompt) {
System.out.print(prompt);
}

/**
* Begin masking until asked to stop.
*/
public void run() {

int priority = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);

try {
stop = true;
while(stop) {
System.out.print("/010" + echochar);
try {
// attempt masking at this rate
Thread.currentThread().sleep(1);
}catch (InterruptedException iex) {
Thread.currentThread().interrupt();
return;
}
}
} finally { // restore the original priority
Thread.currentThread().setPriority(priority);
}
}

/**
* Instruct the thread to stop masking.
*/
public void stopMasking() {
this.stop = false;
}
}

在上边的程序我们看到,利用String数据类型来存储Password这样的敏感信息是不合适的,String对象是不可改变的,并且在用过之后是不可重写的,因此下边会用Char型来代替.

PasswordField.java

import java.io.*;
import java.util.*;

/**
* This class prompts the user for a password and attempts to mask input with "*"
*/

public class PasswordField {

/**
*@param input stream to be used (e.g. System.in)
*@param prompt The prompt to display to the user.
*@return The password as entered by the user.
*/

public static final char[] getPassword(InputStream in, String prompt) throws IOException {
MaskingThread maskingthread = new MaskingThread(prompt);
Thread thread = new Thread(maskingthread);
thread.start();

char[] lineBuffer;
char[] buf;
int i;

buf = lineBuffer = new char[128];

int room = buf.length;
int offset = 0;
int c;

loop: while (true) {
switch (c = in.read()) {
case -1:
case '/n':
break loop;

case '/r':
int c2 = in.read();
if ((c2 != '/n') && (c2 != -1)) {
if (!(in instanceof PushbackInputStream)) {
in = new PushbackInputStream(in);
}
((PushbackInputStream)in).unread(c2);
} else {
break loop;
}

default:
if (--room < 0) {
buf = new char[offset + 128];
room = buf.length - offset - 1;
System.arraycopy(lineBuffer, 0, buf, 0, offset);
Arrays.fill(lineBuffer, ' ');
lineBuffer = buf;
}
buf[offset++] = (char) c;
break;
}
}
maskingthread.stopMasking();
if (offset == 0) {
return null;
}
char[] ret = new char[offset];
System.arraycopy(buf, 0, ret, 0, offset);
Arrays.fill(buf, ' ');
return ret;
}
}

最后给出上述修正后的代码的一个应用PasswordApp Class

// PasswordApp.java

import java.io.*;

public class PasswordApp {
public static void main(String argv[]) {
char password[] = null;
try {
password = PasswordField.getPassword(System.in, "Enter your password: ");
} catch(IOException ioe) {
ioe.printStackTrace();
}
if(password == null ) {
System.out.println("No password entered");
} else {
System.out.println("The password entered is: "+String.valueOf(password));
}
}
}
===================================================
注:本文转自http://java.sun.com,原始文章:http://java.sun.com/developer/technicalArticles/Security/pwordmask/
原作者:Qusay H. Mahmoud
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: