gpt4 book ai didi

无需 servlet 的 Java 客户端身份验证

转载 作者:行者123 更新时间:2023-12-02 11:37:57 24 4
gpt4 key购买 nike

我已经开发了一个独立的应用程序,现在我想执行身份验证

其中一种方法是使用 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还是新手。

最佳答案

在开发身份验证时,我遵循了此 guide 。它描述了密码如何被黑客攻击以及您需要采取哪些措施来保护用户密码。提供一些有关哈希过程的好技巧。简而言之:

  • 仅存储密码的哈希值(和盐,见下文)
  • 使用现有的哈希函数 - 它们比发明自己的哈希更好
  • 带盐的哈希值 - 盐是随机的,因此即使相同的密码也会有不同的哈希值
  • 每次更改密码都必须生成盐

因此在数据库中您需要 2 - 3 列

  • 登录名
  • 密码哈希
  • 盐(如果未合并到密码哈希中)

身份验证将从提供的密码(和存储的盐)创建哈希值,并将其与存储的哈希值(在指定的登录名下)进行比较。无效登录名或密码的错误消息应该相同(无效的用户名或密码),这样不容易找到用户名。

在幕后我的身份验证方法如下所示:

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 只是读取用户表并将其作为 User 对象返回。

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 ,但您需要一些已设置的基础设施才能连接到它。

关于无需 servlet 的 Java 客户端身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48786813/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com