问题描述
我已经开发了一个独立的应用程序,现在我想执行身份验证
I have already developed a standalone app and now i would like to perform authentication
其中一种方法是使用servlet,但我希望我的应用程序是独立的应用程序,不需要与服务器进行通信.
One of the ways would be to use a servlet but i would like my application to be standalone app which doesnt need to communicate with the server.
所以我的登录代码是
//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数据库,因此密码可以存储在此处,但是我想以散列形式存储它,以便用户无法直接看到密码
Does anyone has a clue on how i should proceed.App can connect directly to a mysql or mssql database hence the password can be stored there but i want store it in a hashed form so that a user cannot directly see the password
我该如何处理这种情况.对于Java还是陌生的.
How do i handle such a situation.Am still new to java.
推荐答案
在开发身份验证时,我遵循了指南.它描述了如何破解密码以及保护用户密码所需采取的措施.提供了有关哈希过程的一些很好的技巧.简而言之:
When developing authentication I followed this guide.It describes how passwords are hacked and what you need to do to protect user passwords. Provides some good tips on hashing process.In short:
- 仅存储密码的哈希值(和盐,请参见下文)
- 使用现有的哈希函数-比发明自己的哈希更好
- 加盐的哈希-盐是随机的,因此即使相同的密码也将具有不同的哈希值
- 每次更改密码都必须生成盐
因此在数据库中,您需要2到3列
So in database you need 2 - 3 columns
- 登录名
- 密码哈希
- 盐(如果未合并到密码哈希中)
身份验证将从提供的密码(和存储的盐)中创建哈希,并将其与存储的哈希(在指定的登录名下)进行比较.错误的登录名或密码的错误消息应该相同(无效的用户名或密码),因此不容易找到用户名.
Authentication will create hash from provided password (and stored salt) and compare it to stored hash (under specified login name). Error message for invalid login name or password should be same (invalid user name or password) so it is not easy to find user names.
我的身份验证方法看起来像这样:
Under the hood my authentication method looks like this:
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对象返回.
returning null means either login or password is invalid. UserService simply reads user table and return it as User object.
PasswordManipulator看起来像这样:
PasswordManipulator looks like this:
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 方式.
You probably need some database to embed into your application, or have other way of database setup on client. Check this comparison of embedded databases. To connect to database use standard JDBC way.
问题是,如果用户忘记密码,您将怎么办.标准方法是使用电子邮件进行密码恢复(用户登录名等同于电子邮件或电子邮件是必需的用户信息),但是需要在线连接.可能有一些密码恢复备份问题,用户必须正确回答.或者,如果您具有某种形式的管理用户,则管理用户可以为标准用户重置密码.
Question is what will you do if user will forget password. Standard way is to use email for password recovery (and user login to be equal to email or email to be required user information), but that require online connection. Maybe have some password recovery backup questions that user has to answer correctly. Or if you have some form of administrative user, administrative user could reset passwords for standard users.
还有其他身份验证方式,例如使用活动目录,但是您需要已经建立一些基础架构来连接它.
There are also other ways of authentication like using Active directory, but you need some infrastructure already set up to connect to it.
这篇关于没有Servlet的Java客户端身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!