Developing a simple JDBC servlet log-in applicatio

2019-09-18 07:42发布

问题:

Let me begin by saying that I am not a developer by profession and that this is just something I am learning to do out of interest and too much free time. I am a beginner and I needed to get that out of the way in case I get flack for asking such a simple question.

I am trying to make a "Choose Your Own Adventure" web game, incorporating a login feature for practice. I am using Eclipse Mars, running on Tomcat 8.0. I created a table in my MySql database called PLAYER with the fields id, username, and password. So far, I've created the following files: index.html (which houses the login form), menu.html (the landing page after successful login), and Login.java (a servlet to handle database connection and user authentication).

Here's a portion of the index.html:

<form method="post" action="Login">
    <div class="form_layout">
        <label>User name:</label>
        <input type="text" id="uname" style="width:100%"/>
        <label>Password:</label>
        <input type="password" id="pword" style="width:100%"/>
        <input type="submit" id="login_btn" value="LOGIN" />
</div>      
</form>

Here is all of Login.java:

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.*;

@WebServlet("/Login")
public class Login extends HttpServlet {
    private static final long serialVersionUID = 1L;

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username = request.getParameter("uname");
    String password = request.getParameter("pword");

    String driver = "com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://localhost/game"+"?verifyServerCertificate=false"+"&useSSL=true";
    String user = "root"; 
    String pass = "password";
    String sql = "SELECT username, password FROM player WHERE username = ? AND password = ?";

    Connection connection = null;
    PreparedStatement statement = null;
    ResultSet resultSet = null;
    boolean login = false;

    try {
        Class.forName(driver); 
        connection = DriverManager.getConnection(url, user, pass);
        statement = connection.prepareStatement(sql);
        statement.setString(1, username);
        statement.setString(2, password);
        resultSet = statement.executeQuery();
        login = resultSet.next();
    } catch (Exception e) {
        throw new ServletException("Login failed", e);
    } finally {
        if (resultSet != null) try { resultSet.close(); } catch (SQLException ignore) {}
        if (statement != null) try { statement.close(); } catch (SQLException ignore) {}
        if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
    }

    if (login) {
        request.getSession().setAttribute("username", username); 
        response.sendRedirect("menu.html");
    } else {
        request.setAttribute("message", "Unknown username/password, try again");
        request.getRequestDispatcher("index.html").forward(request, response);
    }
}

}

Every time I try to log in, I always get redirected to index.html, whether or not the credentials I put in are correct. I tried changing this:

else {
    request.setAttribute("message", "Unknown username/password, try again");
    request.getRequestDispatcher("index.html").forward(request, response);
}

to this:

else {
    request.setAttribute("message", "Unknown username/password, try again");
    request.getRequestDispatcher("menu.html").forward(request, response);
}

to see if the redirects were working and found that it bypasses the if statement and proceeds right to else. I guessed that 'login' did not return true, and that's why it won't redirect the way I want it to. Looking at the code now, I honestly don't know what I'm doing wrong. I've scoured the internet for answers, but I've come up with nothing that fixed this for me.

Any sort of help will be appreciated. Thanks!

回答1:

(this is not direct answer to your question, but I don't have enough reputation to comment)

Implementing login by your own is a security risk. The user could enter the /menu.html url and will see the page without login ("deeplink"). Another problem here is the storage of the plain passwords. Its better to save a hash.

Tomcat offers a login mechanism: https://tomcat.apache.org/tomcat-8.0-doc/realm-howto.html

In the web.xml you can define protected areas, which can only be accessed authenticated users. For authentication you can use the JDBCRealm, which performs a user-lookup in the database.



回答2:

Solved this. The query was correct, but the ResultSet returned empty because for some reason, the value from input name = "pword" could not be read (returning null when I tried to print its value to the console), therefore not finding a match in the database. Thought it had something to do with the input being type password (which is weird because it should work that way). What I did was I changed input type to text, and that worked, except the characters in my the password field on my form could be seen. Changed it back to input type = password, and that somehow fixed my problem. No idea why that happened, but the redirects are working now. Thanks to everyone who helped!



回答3:

I found another thing: the input elements in the form do not have names. The servlet tries to get them from request by their id, but what gets submitted in the request is the name of the input element.


outdated (wrong) idea:

I think now I found the mistake: you are comparing Strings in your query with "=" in sql it is LIKE...

String sql = "SELECT username, password FROM player WHERE username LIKE ? AND password LIKE ?";