here is my first virsion question: https://codereview.stackexchange.com/questions/286187/is-it-good-practice-to-have-all-my-back-end-in-one-single-file-with-all-function
```
import java.sql.Statement;
import java.sql.Timestamp;



import java.sql.PreparedStatement;
import java.io.UnsupportedEncodingException;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import java.security.spec.InvalidKeySpecException;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;



//data base consists of columns [ID, username, password, numOfPasswordChanges, passwordChangeTimer]
public class DataBaseController {
    private static final int MAX_USERNAME_LENGTH = 20;
    private static final int MIN_USERNAME_LENGTH = 5;

    private static final int MAX_PASSWORD_LENGTH = 30;
    private static final int MIN_PASSWORD_LENGTH = 7;

    public static final int CORRECT_PASSWORD_RETURN_VAL  = 1;
    public static final int INCORRECT_PASSWORD_RETURN_VAL = 2;
    public static final int MAX_PASSWORD_RESETS_REACHED_RETURN_VAL = 3;

    public static final int WEAK_PASSWORD_RETURN_VAL = 4;
    public static final int WEAK_USERNAME_RETURN_VAL = 5;
    public static final int USER_ALREADY_EXISTS_RETURN_VAL = 6;
    public static final int USER_NOT_EXISTS_RETURN_VAL = 7;    
    

    private static final int USERNAME_INDEX = 2;
    private static final int PASSWORD_INDEX = 3;
    private static final int PASSWORD_RESET_INDEX = 4;
    private static final int RESET_TIMER_INDEX = 5;

    private static final int MAX_PASSWORD_RESETS = 3;

    private static final long RESET_TIME_TO_ADD = 20000L;
    
    private static final String ROOT_NAME = "root";       
    private static final String DB_PASSWORD = "root";
    private static final String DB_NAME = "mydb";
    Connection con;

    public DataBaseController() throws SQLException, ClassNotFoundException {
            Class.forName("com.mysql.jdbc.Driver");
            this.con = DriverManager.getConnection("jdbc:mysql://localhost:3306/" + DB_NAME, ROOT_NAME,DB_PASSWORD);
    }

    public boolean authorizeUser(String username, String password) throws Exception {


            String hashedPassword = new String(passwordHash(password), "UTF-8");
            System.out.println(hashedPassword);
            String query = "SELECT * FROM users WHERE username=?";
            PreparedStatement stmt = this.con.prepareStatement(query);

            stmt.setString(1, username);
            ResultSet rs = stmt.executeQuery();
            
            boolean userExists = rs.next();
            boolean correctLogin = false;
            if(userExists) {
                correctLogin = rs.getString(USERNAME_INDEX).equals(username) && rs.getString(PASSWORD_INDEX).equals(hashedPassword); 
            }

            return correctLogin;

    }

    public int register(String username, String password) throws ClassNotFoundException, SQLException, NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        if(!checkIfUsernameValid(username)) {
            return WEAK_USERNAME_RETURN_VAL;
        }
        
        if(!checkIfPasswordValid(password)) {
            return WEAK_PASSWORD_RETURN_VAL;
        }

        String hashedPassword = new String(passwordHash(password), "UTF-8");
        String query = "SELECT * FROM users WHERE username = ?";
        PreparedStatement stmt = this.con.prepareStatement(query);
        stmt.setString(1, username);
        ResultSet rs = stmt.executeQuery();
        boolean doesUserExists = rs.next();
        
        
        if(!doesUserExists) {
            Statement idCheck = con.createStatement();
            String numberOfUsersQuery = "SELECT COUNT(*) FROM users";
            ResultSet userIDRs = idCheck.executeQuery(numberOfUsersQuery);
            String addUserSql = "";

            userIDRs.next();
            int newID = 1 + userIDRs.getInt(1);

            addUserSql = "INSERT INTO users(ID, username, password) VALUES(?, ?, ?)";
            stmt = this.con.prepareStatement(addUserSql);
            stmt.setInt(1, newID);
            stmt.setString(2, username);
            stmt.setString(3, hashedPassword);
            stmt.executeUpdate();

        }
        if(doesUserExists) {
            return USER_ALREADY_EXISTS_RETURN_VAL;
        }
        return USER_NOT_EXISTS_RETURN_VAL;
    }

    public int resetPassword(String username, String oldPassword, String newPassword) throws ClassNotFoundException, SQLException, UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeySpecException {

        String checkUserQuery = "SELECT * FROM users WHERE username = ? AND password = ?";
        PreparedStatement stmt = this.con.prepareStatement(checkUserQuery);
        stmt.setString(1, username);
        String oldPasswordHashed = new String(passwordHash(oldPassword), "UTF-8");
        stmt.setString(2, oldPasswordHashed);
        ResultSet rs = stmt.executeQuery();
        if(!rs.next()) {
            return INCORRECT_PASSWORD_RETURN_VAL;
        }

        if(!checkIfPasswordValid(newPassword)) {
            return WEAK_PASSWORD_RETURN_VAL;
        }

        String newPasswordHashed = new String(passwordHash(newPassword), "UTF-8");
        int numOfChanges = rs.getInt(PASSWORD_RESET_INDEX);
        Timestamp usersResetTimer = rs.getTimestamp(RESET_TIMER_INDEX);
        System.out.println(usersResetTimer + " **** " + new Timestamp(System.currentTimeMillis()) + " **** " + usersResetTimer.after(new Timestamp(System.currentTimeMillis())));
        if(!usersResetTimer.after(new Timestamp(System.currentTimeMillis()))) {
            numOfChanges = 0;
        }
        if(numOfChanges >= MAX_PASSWORD_RESETS) {
            return MAX_PASSWORD_RESETS_REACHED_RETURN_VAL;
        }

        
        String query = "UPDATE users SET password = ? WHERE username = ?"; 
        try {
            stmt = this.con.prepareStatement(query);
            stmt.setString(1, newPasswordHashed);
            stmt.setString(2, username);
            stmt.executeUpdate();

            numOfChanges += 1;
            query = "UPDATE users SET numOfPasswordChanges = ? WHERE username = ?";
            stmt = this.con.prepareStatement(query);
            stmt.setInt(1, numOfChanges);
            stmt.setString(2, username);
            stmt.executeUpdate();

            Timestamp newUserResetTimer = new Timestamp(System.currentTimeMillis() + RESET_TIME_TO_ADD);
            System.out.println(newUserResetTimer);
            String timeWithoutMillis = newUserResetTimer.toString().split("\\.")[0];
            System.out.println(newUserResetTimer.toString());

            query = "UPDATE users SET passwordChangeTimer = ? WHERE username = ?";
            stmt = this.con.prepareStatement(query);
            stmt.setString(1, timeWithoutMillis);
            stmt.setString(2, username);
            stmt.executeUpdate();

            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return CORRECT_PASSWORD_RETURN_VAL;

    }

    private static boolean checkIfUsernameValid(String username) {
        if( username == null || username.length() > MAX_USERNAME_LENGTH || username.length() < MIN_USERNAME_LENGTH)
        {
            return false;
        }

        for(int i = 0; i < username.length(); i++) {
            if(!Character.isLetter(username.charAt(i)) && !Character.isDigit(username.charAt(i))) {
                return false;
            }
        }

        return true;

    }

    private static boolean checkIfPasswordValid(String password) {
        if(password == null || password.length() > MAX_PASSWORD_LENGTH || password.length() < MIN_PASSWORD_LENGTH) {
            return false;
        }

        boolean symbolFlag = false;
        boolean digitFlag = false;
        boolean letterFlag = false;

        for(int i = 0; i < password.length(); i++) {
            if(!Character.isLetter(password.charAt(i)) && !Character.isDigit(password.charAt(i))) {
                symbolFlag = true;
            }

            if(Character.isLetter(password.charAt(i))) {
                letterFlag = true;
            }

            if(Character.isDigit(password.charAt(i))) {
                digitFlag = true;
            }

            if(symbolFlag && digitFlag && letterFlag) {
                return true;
            }
        }

        return false;
    }

    private static byte[] passwordHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        byte[] hash = messageDigest.digest(password.getBytes("UTF-8"));
        return hash;
        
    }

}
```

I already posted here about this project before, got feedback and want to know if the problems still persist.
so I changed to prepared statement to avoid sql injecntion,
I also cached my DB connection in the constructor,
and finally I hashed my passwords and then sent them to the data base.
did I implement it correctly?
I also tried salting my passwords but I couldnt figure out how, for some reason whenever I remove the salt from the hashed password it doesnt keep its structure (I hashed a password, added salt to it and when I hash the same password and remove the salt it is not the same if I remove the salt from the original)
so for now only SHA-256.
     
**what my code tries to achieve**    
I tried building a backed with a connection to a Database in my case I used MySQL.    
so far I implemented authorizationg, regitration and password resets.    
and addition to them I recently added a password hashing function but I wasnt able to add salt to it.    
    

**what my code does**    
first of all I have a bunch of files that are simple GUI for example the login and password page, and this file is where my backend.
I have a constructor that creates a connection to my database once and each file that needs access to the backend creates an instance of it.    
the columns in MySQL table are as follows in the same order: ID (unique key), username, password, numOfPasswordChanges, passwordChangeTimer

                
**_authorizeUser_**      
first function is authorizeUser which take in a username and a password
I use PreparedStatement to query my database so that it'll be more secure against SQL injection.    
     
this is how I do the query to check for existing user.
```
String hashedPassword = new String(passwordHash(password), "UTF-8");

            String query = "SELECT * FROM users WHERE username=?";
            PreparedStatement stmt = this.con.prepareStatement(query);

            stmt.setString(1, username);
            ResultSet rs = stmt.executeQuery();
```

here I check if the password is correct   
```
boolean userExists = rs.next();
            boolean correctLogin = false;
            if(userExists) {
                correctLogin = rs.getString(USERNAME_INDEX).equals(username) && rs.getString(PASSWORD_INDEX).equals(hashedPassword); 
            }

```
    
**_register_**    
first of all it checks if given username and password are strong enough (for password I plan on using regex but still havent got around to it),
then hashes the password that the user gives.    
```
        String hashedPassword = new String(passwordHash(password), "UTF-8");
        String query = "SELECT * FROM users WHERE username = ?";
        PreparedStatement stmt = this.con.prepareStatement(query);
        stmt.setString(1, username);
        ResultSet rs = stmt.executeQuery();
        boolean doesUserExists = rs.next();
```
   
if user not exists it proceeds to add the new user to the DB    
```
if(!doesUserExists) {
            Statement idCheck = con.createStatement();
            String numberOfUsersQuery = "SELECT COUNT(*) FROM users";
            ResultSet userIDRs = idCheck.executeQuery(numberOfUsersQuery);
            String addUserSql = "";

            userIDRs.next();
            int newID = 1 + userIDRs.getInt(1);

            addUserSql = "INSERT INTO users(ID, username, password) VALUES(?, ?, ?)";
            stmt = this.con.prepareStatement(addUserSql);
            stmt.setInt(1, newID);
            stmt.setString(2, username);
            stmt.setString(3, hashedPassword);
            stmt.executeUpdate();

        }
```  
   
**_resetPassword_**    
here I check for correct provided oldPassword with a PreparedStatement, then check if new password strong enough, ```int numOfChanges = rs.getInt(PASSWORD_RESET_INDEX);``` takes in the amount of tries the user tried to reset the password.     
     
here I create a TimeStamp object to check if the timeout on resets has reached (currently 20 seconds after 3 resets).    
then im setting the new password for the user.   
         
```
Timestamp usersResetTimer = rs.getTimestamp(RESET_TIMER_INDEX);

        if(!usersResetTimer.after(new Timestamp(System.currentTimeMillis()))) {
            numOfChanges = 0;
        }
        if(numOfChanges >= MAX_PASSWORD_RESETS) {
            return MAX_PASSWORD_RESETS_REACHED_RETURN_VAL;
        }
```
 
here I update the amount of reset tries.     

```
            numOfChanges += 1;
            query = "UPDATE users SET numOfPasswordChanges = ? WHERE username = ?";
            stmt = this.con.prepareStatement(query);
            stmt.setInt(1, numOfChanges);
            stmt.setString(2, username);
            stmt.executeUpdate();
```

and finally updating the timeout time in the DB
```
Timestamp newUserResetTimer = new Timestamp(System.currentTimeMillis() + RESET_TIME_TO_ADD);
            System.out.println(newUserResetTimer);
            String timeWithoutMillis = newUserResetTimer.toString().split("\\.")[0];
            System.out.println(newUserResetTimer.toString());

            query = "UPDATE users SET passwordChangeTimer = ? WHERE username = ?";
            stmt = this.con.prepareStatement(query);
            stmt.setString(1, timeWithoutMillis);
            stmt.setString(2, username);
            stmt.executeUpdate();
```
the return values of all of those functions are for the front end.    
    
I also have this as my password hashing function
```
    private static byte[] passwordHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        byte[] hash = messageDigest.digest(password.getBytes("UTF-8"));
        return hash;
        
    }
```