This question already has answers here:
Pass data between classes
(2 answers)
Closed 5 years ago.
Given a login window which requires 2 inputs from the user: username & password.
After being identified successfully the user gets redirected to the main window.
Here I want to display his or her username but I'm receiving null.
This is my current code:
Login class:
private void LoginUser(String username, String password)
{
user = username;
pass = password;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try
{
conn = MainEngine.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT username FROM users WHERE username ='"+user+"' AND password ='"+getMD5Hex(pass)+"'");
if(rs.next()) // Successful login
{
Window_AfterLogin window_afterlogin = new Window_AfterLogin();
window_afterlogin.setVisible(true);
this.dispose();
}
else
{
label_info.setText("Wrong credentials");
}
}
catch(Exception e)
{
System.err.println(e);
}
}
public String getUserName()
{
return user;
}
Note: user and pass variables are global.
Window_AfterLogin class:
public Window_AfterLogin() {
initComponents();
Window_Login window_login = new Window_Login();
System.out.println(window_login.getUserName());
}
Your Window_AfterLogin() constructor initializes another Window_Login which means there is the username, which you try to retrieve by window_login.getUserName() - null.
In your after login code you could add another field username:
public Window_AfterLogin{
private String username;
public Window_AfterLogin(String username){
initComponents();
this.username = username;
}
}
Where inside your LoginUser class you have to change the code accordingly:
if(rs.next()) // Successful login
{
Window_AfterLogin window_afterlogin = new Window_AfterLogin(user);
window_afterlogin.setVisible(true);
this.dispose();
}
Note:
Your application is vulnerable to SQL-Injections. Please read about prepared statements and how SQL-Injections work in theory and try to prevent them.
https://de.wikipedia.org/wiki/SQL-Injection
https://www.tutorialspoint.com/javaexamples/jdbc_prepared_statement.htm
In the constructor, you are creating a new instance of the Window_Login class and not setting the username.
Related
I am doing username and password check against MySQL database but somehow my code is returning none even for the base case (email does not exist). I hash my passwords on the server side. What should I fix in this case?
package GUI_755;
import java.sql.*;
import nonGUI_755.AES;
public class test {
public static void main(String args[]) throws Exception {
System.out.println(loginResponse("jordan30#bulls.edu","JordanTheGoat3098"));
}
/* The method handles the login's request from the user */
public static String loginResponse(String email, String password) throws Exception{
String returnStatement = "";
Connection connection = null;
connection = establishConnection();
/* Similar to the code above, we check whether the email and password match to those we have in the database */
final String queryCheck = "SELECT * from usersdata WHERE email = ?";
final PreparedStatement ps = connection.prepareStatement(queryCheck);
ps.setString(1, email);
final ResultSet resultSet = ps.executeQuery();
try {
/* First, if we cannot find the user's email, we return this statement */
if(email.equals(resultSet.getString("email"))) {
/* Second, if we can find the email but the password do not match then we return that the password is incorrect */
String hashedPasswordInput = AES.doHash(password, resultSet.getObject("password").toString().split("\t")[1]);
if(hashedPasswordInput.equals(resultSet.getObject("password").toString().split("\t")[0])) {
returnStatement = "LoginFailure The password that you entered is incorrect. Please try again!";
connection.close();
}
else {
returnStatement = "LoginSuccess You are logged in!";
}
}
else {
connection.close();
returnStatement = "LoginFailure We cannot find any account associated with that email. Please try again!";
}
}catch(Exception e) {}
return returnStatement;
}
/* This method will connect to MySQL database >> userdata */
public static Connection establishConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/userdata","root","");
return connection;
}catch(Exception e)
{return null;}
}
}
You need to check if your ResultSet resultSet is returning some rows. For that, you should use next() method of ResultSet. You can use if (resultSet.next() if you are interested in only first row (like your case here) or while (resultSet.next()) if you want to loop over the returned result rows (not your case).
So to put it together:
final String queryCheck = "SELECT * from usersdata WHERE email = ?";
final PreparedStatement ps = connection.prepareStatement(queryCheck);
ps.setString(1, email);
final ResultSet resultSet = ps.executeQuery();
if (resultSet.next()) {
/* First, if we cannot find the user's email, we return this statement */
if(email.equals(resultSet.getString("email"))) {
/* Second, if we can find the email but the password do not match then we return that the password is incorrect */
String hashedPasswordInput = AES.doHash(password, resultSet.getObject("password").toString().split("\t")[1]);
if(hashedPasswordInput.equals(resultSet.getObject("password").toString().split("\t")[0])) {
// dont do it here
// returnStatement = "LoginFailure The password that you entered is incorrect. Please try again!";
// connection.close();
}
else {
returnStatement = "LoginSuccess You are logged in!";
}
}
else {
// don't do it here
// connection.close();
// returnStatement = "LoginFailure We cannot find any account associated with that email. Please try again!";
}
}
first of all I know this is duplicated question. But I've search and tried from stackoverflow listed on Google to quora but still cant resolve my Get method still return null.
This is my class loginModel.java under package com.hello.model
public class loginModel {
public String username;
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return this.username;
}
}
This is my loginView.java under package com.hello.view
import com.hello.model.loginModel;
public class loginView extends javax.swing.JFrame {
loginModel login = new loginModel();
public loginView() {
initComponents();
this.setLocationRelativeTo(null);
loginFunction();
}
private void loginFunction(){
String username = usernameText.getText();
String password = passwdText.getText();
String query = "select * from access where username = '" +username+ "' AND password = '" +password+"'";
databaseConnect db = new databaseConnect();
try (Connection con = DriverManager.getConnection(db.url, db.user, db.password);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query)) {
if(rs.next()) {
if(username.equals(rs.getString("username")) && password.equals(rs.getString("password"))){
JOptionPane.showMessageDialog(null, "login Success");
String name = rs.getString("name");
String privilege = rs.getString("privilege");
login.setUsername(name);
menu = new menuView();
menu.setVisible(true);
this.setVisible(false);
}
} else {
JOptionPane.showMessageDialog(null, "username or password incorrect");
}
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
I want call my username from menuView.java under package com.hello.view after login success
import com.hello.model.loginModel;
import com.hello.view.loginView;
public class menuView extends javax.swing.JFrame {
private String username;
loginModel login = new loginModel();
public menuView() {
initComponents();
this.setLocationRelativeTo(null);
initMenu();
}
private void initMenu(){
username = login.getUsername();
JOptionPane.showMessageDialog(this, username);
}
}
As per my question when I call Get method from loginModel, messagebox return null.
I've tried:
Put system.out.println directly in loginModel.java, value return
and call system.out.println in menuView.java at the same time but value return null. How?
Send string between jframe with menu = menuView(username) in loginView.java and retrieve in menuView.java, value return null
Using no model and create set string in loginView and call it in
menuView, value return null
I need values that I want to use in another class/package/jframe. Am I doing wrong?
I am not well versed in Swing but I can see the problem, just not the exact solution.
Your code creates an instance of loginModel in both the menuView and in loginView. Then in loginView is sets the name in the instance it has, in in menuView it gets the name from its own instance.
You need to create a single instance of the model and share it between the two views.
In a pojo way I would pass the loginModel to both "views" in a constructor.
menu = new menuView(login);
And in menuView
public menuView(loginModel login) {
this.login = login;
}
Your menuView instance isn't using the loginModel class that you instantiate in loginView, it's using the new one you created using new menuView() when you initialized the login variable in the menuView class. You just need to add a setter method for the loginModel attribute in the menuView class like this:
import com.hello.model.loginModel;
import com.hello.view.loginView;
public class menuView extends javax.swing.JFrame {
private String username;
loginModel login = new loginModel();
public menuView() {
initComponents();
this.setLocationRelativeTo(null);
initMenu();
}
private void initMenu(){
username = login.getUsername();
JOptionPane.showMessageDialog(this, username);
}
public void setLogin(loginModel loginModel) {
this.login = loginModel;
}
}
Then call the setter in loginView.loginFunction like this:
... code before
login.setUsername(name);
menu = new menuView();
menu.setLogin(login);
menu.setVisible(true);
this.setVisible(false);
... code after
Notice the only changes to your code are the added setLogin method on the menuView class and the call to menu.setLogin(login) in loginView.loginFunction.
You need to think in stages/steps. Login is a single step, it has one of two outcomes, success or failure.
Your app needs to perform this step and take appropriate action based on the outcome of the result.
You also need to think about "separation of responsibility" - in this case, it's not really the responsibility of the loginView to perform the login operation, it just coordinates the user input.
The responsibility actually falls to the LoginModel
// Just a custom exception to make it easier to determine
// what actually went wrong
public class LoginException extends Exception {
public LoginException(String message) {
super(message);
}
}
// LoginModel ... that "does" stuff
public class LoginModel {
private String username;
DatabaseConnect db;
public LoginModel(DatabaseConnect db) {
this.db = db;
}
// I would consider not doing this. You need to ask what reasons would
// the app need this information and expose it only if there is really a
// reason to do so
public String getUsername() {
return username;
}
public boolean isLogedIn() {
return username != null;
}
public void validate(String username, String password) throws SQLException, LoginException {
String query = "select * from access where username = ? AND password = ?";
try ( Connection con = DriverManager.getConnection(db.url, db.user, db.password); PreparedStatement st = con.prepareStatement(query)) {
st.setString(1, username);
st.setString(2, password);
try ( ResultSet rs = st.executeQuery()) {
if (rs.next()) {
this.username = username;
} else {
throw new LoginException("Invalid user credentials");
}
}
}
}
}
This is an overly simplified example, as the actual responsibility for performing the login should fall to the controller, which would then generate the model, but I'm getting ahead of myself.
Because the flow of the app shouldn't be controlled/determined by the login view, the LoginView should itself be a dialog. This way, it can be shown when you need it, it can perform what ever operations it needs and then go away, leaving the rest of the decision making up to who ever called it
public class LoginView extends javax.swing.JDialog {
private LoginModel model;
public LoginView(LoginModel model) {
initComponents();
setModal(true);
this.model = model;
this.setLocationRelativeTo(null);
}
// This will get executed when the user taps some kind of "perform login button"
private void loginFunction() {
String username = usernameText.getText();
String password = passwdText.getText();
try {
model.validate(username, password);
dispose()
} catch (SQLException ex) {
// This should probably be considered a fatal error
model = null;
dispose();
} catch (LoginException ex) {
JOptionPane.showMessageDialog(this, "Login vaild");
}
}
}
This then means you might put it together something like this...
DatabaseConnect db = new DatabaseConnect();
LoginModel model = new LoginModel(db);
LoginView loginView = new LoginView(model);
// Because we're using a modal dialog, the code execution will wait here
// till the window is disposed/closed
loginView.setVisible(true);
if (loginView.model != null) {
// model is now valid and can continue to be used
// in what ever fashion you need
} else {
JOptionPane.showMessageDialog(null, "Fatal Error");
}
This takes you a step closer to a more decoupled solution, where you feed information to the classes when they need it, rather than the classes making decisions about what they should create/use.
It also moves you a step closer to re-usable classes, as they do their specific job and nothing more.
You might find taking the time to read up on "model-view-controller" will help you better understand this approach
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 1 year ago.
I have been trying to redirect the user that has logged into the system to their respective page after checking their email and password. But i am not sure about the logic behind that coding and when i try it it just response with the else statement. I have tried the validation of the email and password and that works fine and redirects to the correct page, but when i add the user type condition it doesnt work
I have tried including nested if statements, but i am not sure about its logic,it always executes the else statement.
loginControllerServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String email=request.getParameter("email");
String password=request.getParameter("pwrd");
User theUser=loginDbUtil.gettype(email);
if(loginDbUtil.check(email, password))
{
String p="pharmacist";
if(theUser.getType()==p)
{
// HttpSession session=request.getSession();
// session.setAttribute("email", email);
response.sendRedirect("medicine.jsp");
}
else
{
response.sendRedirect("index.jsp");
}
}else
{
response.sendRedirect("index.jsp");
}
}
}
loginDbUtil.java
public boolean check(String email,String password)
{
Connection myConn=null;
PreparedStatement myStmt=null;
ResultSet rs=null;
try
{
//get db connection
myConn=dataSource.getConnection();
//sql statemtn
String sql="select email,pass from usertab where email=? and pass=? ";
myStmt=myConn.prepareStatement(sql);
//set the param values for user
myStmt.setString(1, email);
myStmt.setString(2, password);
rs=myStmt.executeQuery();
if(rs.next())
{
return true;
}
}catch(Exception e)
{
e.printStackTrace();
}
return false;
}
public User gettype(String email) {
User type=null;
Connection myConn=null;
PreparedStatement myStmt=null;
ResultSet rs=null;
try
{
//get db connection
myConn=dataSource.getConnection();
//sql statemtn
String sql="select type from usertab where email=? ";
myStmt=myConn.prepareStatement(sql);
//set the param values for user
myStmt.setString(1, email);
rs=myStmt.executeQuery();
if(rs.next())
{
String t=rs.getString("type");
type =new User(t);
}
}catch(Exception e)
{
e.printStackTrace();
}
return type;
}
}
What i want is after the email and password is checked then next check for the users data type and redirect them to the correct page
In your loginControllerServlet.java change this to
if(theUser.getType()==p)
to this
if(theUser.getType().equals(p))
According to your logic, I think first of all, you should put the attribute type as an int, there will be less chances to have a type like Pharmacist and pharmacist.
Then to communicate with database check is correct, but I don't think the same about you getType method, this is what I would suggest to you :
1st : Create one bean (object) User as you seem to have done and put getters and setters, and put a constructor with all the attributes as parameters.
Example :
class User {
private int id;
private String mail;
private String password;
private int type;
public User() {
}
public User(int id, String mail, String password, int type) {
this.id = id;
this.mail = mail;
this.password = password;
this.type = type;
}
// Getters and setters
}
Then you check mail would return directly a user object, so you should have
class userDB {
public User login(String mail, String password) {
User user = new User();
String query = "select * from user where mail = ? and password = ?";
try {
PreparedStatement prep = conn.prepareStatement(query);
prep.setString(1,mail);
prep.setString(2,password);
ResultSet res = res.executeQuery();
if(res.first) {
user = new User(res.getInt("id"),res.getString("mail"),res.getString("password"),res.getInt("type"));
return user;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
And then in you Servlet you can write:
class Login extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse respons) throws ServletException, IOException {
this.getServletContext().getRequestDispatcher(your_jsp_relative_path).forward(request, respons);
}
public void doPost(HttpServletRequest request, HttpServletResponse respons) throws ServletException, IOException {
String mail = (String) request.getParameter("mail');
String password = (String) request.getParameter("mail');
User user = new UserDB().login(mail, password);
if(user != null){
int type = user.getType();
switch(type){
case 0 :
respons.sendRedirect("type_0_page");
break;
case 1 :
respons.sendRedirect("type_1_page");
break;
case 2 :
respons.sendRedirect("type_2_page");
break;
default :
repons.sendRedirect("/error500.jsp");
break;
}
}else{
this.getServletContext().getRequestDispatcher(your_jsp_relative_path).forward(request, respons);
}
}
}
I have created the following function which is supposed to check whether the "role" column in my Database contains admin or is Null (which means it's a regular user). I try to test it in my Servlet class as shown in the code below but it redirects me to the USER JSP page every time. Is there any error in my checkRole() method? Thank you in advance.
checkRole() method
public static boolean checkRole() {
boolean find = false;
PreparedStatement pst = null;
ResultSet rs = null;
try(Connection conn= ConnectionConfiguration.getConnection()){
pst = conn.prepareStatement("SELECT * FROM users WHERE role=?;");
pst.setString(1, role);
rs = pst.executeQuery();
while (rs.next()) {
if (rs.getString("role").equals("admin") {
find = true;
} else {find = false;}
}
} catch (SQLException e) {
e.printStackTrace();
}
return find;
}
SERVLET code
{
String pass1 = request.getParameter("password");
String email = request.getParameter("email");
//checks whether user credentials are right and if it is admin
if(User.validate(email,pass1) && User.checkRole()){
request.setAttribute("email",request.getParameter("email"));
request.setAttribute("pass", request.getParameter("password"));
s.invalidate();
forwardTo(ctx, request, response, "/Admin.jsp");
}
//checks whether user credentials are right and if it is a regular user
else if (User.validate(email, pass1) && !User.checkRole()) {
request.setAttribute("email",request.getParameter("email"));
request.setAttribute("pass", request.getParameter("password"));
s.invalidate();
forwardTo(ctx, request, response, "/RegularUser.jsp");
}
else {
//show some error message
}
}
Your checkRole() method will always evaluate to true if you have more than 1 user with different roles in your users table. Because you're selecting all the rows where the field role is of a certain type. And if the certain role type exists in your users table, it will always be true...
Like the other answer has mentioned already, you need to pass a unique identifier. How else is the query supposed to know which user you are checking the role for? In most applications this is done by a user_id/id field, but since you only have email here, you can do use that also. I would do something like this:
public static boolean isAdmin(String email) {
boolean check = false;
PreparedStatement pst = null;
ResultSet rs = null;
try(Connection conn= ConnectionConfiguration.getConnection()){
pst = conn.prepareStatement("SELECT * FROM users WHERE email =? and role='admin';");
pst.setString(1, email);
rs = pst.executeQuery();
check = rs.next(); // if the resultSet has results, then check will evaluate to true
} catch (SQLException e) {
e.printStackTrace();
}
return check;
}
Then for your servlet:
{
String pass1 = request.getParameter("password");
String email = request.getParameter("email");
//first check if valid login details (seperate it out so you can be more specific in the error you give back, and you don't have to repeat yourself)
if(User.validate(email,pass1)){
// s.invalidate(); //this isn't really necessary here, normally you invalidate the session variables when the user logs out. If a different user logs in (whilst one is already logged in), then any session variables you have set would override it.
String url = "/RegularUser.jsp";
String role = "regular";
//now check if user is admin
if(User.isAdmin(email)){
url = "/Admin.jsp"
role = "admin";
}
//set your session variables
//s.setAttribute("user_email", email);
//s.setAttribute("user_role", role);
forwardTo(ctx, request, response, url);
}else{
//wrong login details - set values back in form
request.setAttribute("email",email);
request.setAttribute("pass", pass1);
forwardTo(ctx, request, response, "/Login.jsp");
}
}
In the checkRole() method, you need to break out of the while loop after finding an admin, otherwise your "find" boolean will probably be set to false again on the next iteration.
Change your checkRole method like
public static boolean checkRole(String email) {
boolean find = false;
PreparedStatement pst = null;
ResultSet rs = null;
try(Connection conn= ConnectionConfiguration.getConnection()){
pst = conn.prepareStatement("SELECT * FROM users WHERE email =? and role='admin';");
pst.setString(1, email);
rs = pst.executeQuery();
if(rs.next()) {
find = true;
}
} catch (SQLException e) {
e.printStackTrace();
}
return find;
}
And in your servlet code write if condition like
if(User.validate(email,pass1) && User.checkRole(email))
I am stuck with this for a while and I am not sure how to fix this. The problem is my SQL query does not get the input from javaFX textfield and passwordfield(I am building a login window).
If I enter the values manually rather than getting them from a textfield the program work fine, otherwise nothing happens when you press login button. The problem occurs at the following lines, of course with no error messages:
preparedStatement.setString(1,txtUserName.getText());
preparedStatement.setString(2,txtPassword.getText());
Here is the full code:
public class LoginWindow implements Initializable{
#FXML
private TextField txtUserName;
#FXML
private PasswordField txtPassword;
#FXML
private Button btnLogin;
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
// Setting the login button.
#FXML
private void setBtnLogin(ActionEvent event) {
try {
connection = DBUtilities.getConnection();
String sqlQuery = "SELECT * FROM user_login_details WHERE User_Name = ? AND User_Password = ?";
preparedStatement = connection.prepareStatement(sqlQuery);
preparedStatement.setString(1,txtUserName.getText());
preparedStatement.setString(2,txtPassword.getText());
resultSet = preparedStatement.executeQuery();
if(resultSet.next()) {
DBUtilities.showInforMsg("Logged in:", "You have logged in!");
} else {
DBUtilities.showErrorMsg("Error:", "Invalid username or password");
}
}catch (Exception exception) {
exception.printStackTrace();
}finally {
DBUtilities.closePreparedStatement(preparedStatement);
DBUtilities.closeResultSet(resultSet);
DBUtilities.closeConnection(connection);
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
btnLogin.setOnAction(this::setBtnLogin);
}
}
Thank you very much. I simply did not gave any ID to the passwordfield.
You can debug by first trying to print the string from your input fields:
String username = txtUserName.getText();
String password = txtPassword.getText();
System.out.println("User name = " + username);
System.out.println("Password = " + password);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
If the username and password are null then make sure, those fields controller are well bound to the FXML document.