我已经开发了一个独立的应用程序,现在我想执行身份验证
使用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数据库,因此可以将密码存储在此处,但我希望以哈希形式存储它,以便用户无法直接看到密码
我如何处理这种情况。
开发身份验证时,我遵循本指南。它描述了密码如何被黑客入侵以及您需要采取的措施来保护用户密码。提供了一些有关哈希过程的好提示。简而言之:
- 仅存储您的密码(和盐,请参见下文(
- 使用现有的哈希功能 - 它们比发明自己的哈希 更好
- 搭配盐 - 盐是随机的
- 盐必须为每个密码更改生成
因此,在数据库中,您需要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表示登录或密码无效。用户服务只会读取用户表并将其返回为用户对象。
密码管理器看起来像这样:
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);
}
}
}
}
您可能需要一些数据库嵌入您的应用程序,或在客户端上具有其他数据库设置。检查嵌入式数据库的此比较。要连接到数据库,请使用标准JDBC方式。
问题是,如果用户忘记密码,您将怎么办。标准方法是使用电子邮件进行密码恢复(用户登录为等于电子邮件或电子邮件,以便是用户信息(,但这需要在线连接。也许有一些密码恢复备份问题,用户必须正确回答。或者,如果您有某种形式的管理用户,则可以为标准用户重置密码。
还有其他认证方法,例如使用Active Directory,但是您需要一些已经设置的基础架构才能连接到它。