На некоторых клавиатурах вы должны поставить дополнительные тесты для символов '\ n' и '\ r'.
if(event.getCode().equals(KeyCode.ENTER) || event.getCharacter().getBytes()[0] == '\n' || event.getCharacter().getBytes()[0] == '\r') {
// your action
}
На самом деле, вот реализация Sun getPassword ()
:
public char[] getPassword() {
Document doc = getDocument();
Segment txt = new Segment();
try {
doc.getText(0, doc.getLength(), txt); // use the non-String API
} catch (BadLocationException e) {
return null;
}
char[] retValue = new char[txt.count];
System.arraycopy(txt.array, txt.offset, retValue, 0, txt.count);
return retValue;
}
Единственный getText
, в котором есть вызов getText ( int offset, int length, Segment txt)
, который вызывает getChars (int where, int len, Segment txt)
, который, в свою очередь, копирует символы непосредственно в сегмент Segment
. буфер. Там не создаются Strings
.
Затем буфер Segment
копируется в возвращаемое значение и обнуляется перед возвратом метода.
Другими словами. : Нигде не висит лишняя копия пароля . Это совершенно безопасно, если вы используете его по назначению.
Реализация Swing слишком сложна для проверки вручную. Вам нужны тесты.
public class Pwd {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new javax.swing.JFrame("Pwd") {{
add(new javax.swing.JPasswordField() {
@Override public String getText() {
System.err.println("Awoooga!!");
return super.getText();
}
{
addActionListener(
new java.awt.event.ActionListener() {
public void actionPerformed(
java.awt.event.ActionEvent event
) {
// Nice.
}
}
);
}
});
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setVisible(true);
}};
}
});
}
}
Мне кажется, это командная строка для (бессмысленного) события действия.
Ладно, плохо ... Все колокола зазвонили, как только я увидел вызов getText (), не замечая, что он был фактически введен мной с помощью слушателя действий, вот трассировка стека
PasswordTest$1.getText() line: 14
PasswordTest$1(JTextField).fireActionPerformed() line: not available
PasswordTest$1(JTextField).postActionEvent() line: not available
JTextField$NotifyAction.actionPerformed(ActionEvent) line: not available
SwingUtilities.notifyAction(Action, KeyStroke, KeyEvent, Object, int) line: not available
Вот используемый код:
import java.awt.event.*;
import javax.swing.*;
public class PasswordTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPasswordField passField = new JPasswordField() {
@Override
public String getText() {
System.err.println("Awhooa: " + super.getText()); //breakpoint
return null;
}
};
passField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
char[] p = passField.getPassword();
System.out.println(p);
}
});
frame.add(passField);
frame.setVisible(true);
frame.pack();
}
}
А вот вывод консоли:
Awhooa: secret
secret
И для фактического вызова getPassword (), возможно, я что-то упускаю, но где обнулен буфер сегмента? Я вижу копию массива, но не обнуление. Возвращенный массив будет обнулен мной, но массив сегментов все еще там ...
import java.util.Arrays;
public class ZeroingTest {
public static void main(String[] args) {
char[] a = {'a','b','c'};
char[] b = new char[a.length];
System.arraycopy(a, 0, b, 0, b.length);
System.out.println("Before zeroing: " + Arrays.toString(a) + " " + Arrays.toString(b));
Arrays.fill(a, '\0');
System.out.println("After zeroing: " + Arrays.toString(a) + " " + Arrays.toString(b));
}
}
И вывод:
Before zeroing: [a, b, c] [a, b, c]
After zeroing: [?, ?, ?] [a, b, c]
(я поставил там вопросительные знаки, потому что не могу пропустить непечатаемые символы)
-M
** Я столкнулся с этим, когда искал способ фактически отображать некоторые конфиденциальные данные в компоненте Swing без использования объекта String. Очевидно, нет способа сделать это, если я не захочу переписать часть (все?) Swing API ... этого не произойдет.
Вы можете указать JPasswordField
отображать символы, вызвав field.setEchoChar ('\ 0')
. Это сохраняет остальную защиту, предлагаемую JPasswordField
(без String
s, без вырезания / копирования).