我已经开发了一个独立的应用程序,现在我想执行身份验证
其中一种方法是使用servlet,但我希望我的应用程序是独立的应用程序,不需要与服务器通信。
所以我的登录代码是
//loads the login screen
@Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
primaryStage.setTitle("Login screen");
Scene loginscene = new Scene(root,700, 700);
loginscene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode()){
case ENTER:{
onLogin();
}
}
}
});
primaryStage.setScene(loginscene);
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.getIcons().add(new Image("file:icon.png"));
primaryStage.centerOnScreen();
primaryStage.setResizable(false);
primaryStage.show();
}
登录方法是
onLOgin(){
//here am stuck on how to proceed
}
有没有人知道我应该怎么做。 应用程序可以直接连接到mysql或mssql数据库,因此密码可以存储在那里,但我想以散列形式存储它,以便用户无法直接看到密码
我如何处理这种情况。对于java来说还是新手。
答案 0 :(得分:1)
在开发身份验证时,我遵循了guide。 它描述了如何破解密码以及保护用户密码需要执行的操作。提供有关散列过程的一些好的技巧。 简而言之:
所以在数据库中你需要2到3列
身份验证将根据提供的密码(和存储的salt)创建哈希值,并将其与存储的哈希值(在指定的登录名下)进行比较。无效登录名或密码的错误消息应相同(用户名或密码无效),因此不容易找到用户名。
在幕后,我的身份验证方法如下所示:
public User authenticate(String login, String password) {
final User user = UserService.getInstance().getUser(login);
if(user != null) {
//check password
byte[] passwordHash = PasswordManipulator.instance.hash(password, user.getPasswordSalt());
if(Arrays.equals(passwordHash, user.getPasswordHash())) {
return user;
}
else {
// invalid password, we return no user
return null;
}
}
return null;
}
返回null表示登录或密码无效。 UserService只是读取用户表并将其作为用户对象返回。
PasswordManipulator如下所示:
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class PasswordManipulator {
private static final int SaltLength = 32;
private static final int IterationCount = 65536;
private static final int KeyLength = 256;
private final SecureRandom random = new SecureRandom();
SecretKeyFactory factory = null;
public static final PasswordManipulator instance = new PasswordManipulator();
private PasswordManipulator() {
}
public byte[] createSalt() {
byte[] salt = new byte[SaltLength];
random.nextBytes(salt);
return salt;
}
public byte[] hash(String password, byte[] salt) {
init();
if(password == null || password.isEmpty()) {
throw new IllegalArgumentException("Password is null or empty");
}
if(salt == null ) {
throw new IllegalArgumentException("Salt is null!");
}
if(salt.length != SaltLength) {
throw new IllegalArgumentException("Salt length is not valid. Expected length is " + SaltLength + ", but length is " + salt.length);
}
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, IterationCount, KeyLength);
try {
byte[] hash = factory.generateSecret(spec).getEncoded();
return hash;
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException("Failed to create password hash", e);
}
}
private void init(){
if(factory == null) {
try {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Cannot init " + this.getClass(), e);
}
}
}
}
您可能需要将一些数据库嵌入到您的应用程序中,或者在客户端上设置其他数据库方式。检查嵌入式数据库的this比较。要使用标准JDBC方式连接到数据库。
如果用户忘记密码,您会怎么做?标准方法是使用电子邮件进行密码恢复(并且用户登录等于电子邮件或电子邮件是必需的用户信息),但这需要在线连接。也许有一些用户必须正确回答的密码恢复备份问题。或者,如果您有某种形式的管理用户,管理用户可以重置标准用户的密码。
还有其他一种身份验证方式,例如使用Active directory,但您需要设置一些基础设施来连接它。