let us say i'm having a table(login) that has usernames(unique key) and passwords, used for login purposes.
Now, in the registration module(that creates a new account by adding a new row in login table),is it okay if i just execute the insert and check if the username is already in the table when the SQLException() raises???. is it a good practice???
Here's an example of registration module:
enter code here
String uname = request.getParameter("username");
String passwd = request.getParameter("password");
try
{
statement.executeUpdate("insert into login(username,password) values (" + uname + "," + passwd + ")");
}
catch(SQLException e)
{
if((e.getErrorCode())==1) //error code when primary key violated
{
// username already exists....
}
//some other code
}
//username is available....rest of the code goes here
in the firs place i thought of a select query to check if the username (user has entered while registering) is already in the table....but it seemed redundant to me
because i thought, even doing so wouldnt prevent the DBMS to check the uniqueness violation, right????
Thanks in advance.
What I would recommend is do a validation before insert, in case you change underlying database which change the error code in SQLException.getErrorCode(). This also enable you do validation before user submit the form. You can create a custom exception the notify your service caller that username is already in use.
Retrieves the vendor-specific exception code for this SQLException
object.
SELECT COUNT(*) FROM LOGIN WHERE USERNAME = :username
via a service method, for example:
public class UserService {
public boolean isValidUsername(String username) {
//validate
}
public void registerUser(User user) throws UsernameInUseException {
if(!isValidUsername(user.getUsername()) {
throw new UsernameInUseException("Usernaame " + user.getUsername() + " is already in use.");
}
// continue
}
}
It will be cool if you could tell the user before form submission that username already exists using AJAX calls.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
After Registration, I want to verify the information of the user, After verifying the information by admin - He will be able to log in. How can I do it by JavaFX?
In my code if anyone registers he can login by this time but I want to verify his/her information, if his all information is correct then he will be able to log in for the next activity, otherwise i want to reject his registration.
Here is my database connection snippet:
public static void signUpUser(ActionEvent event, String username, String email, String password) {
Connection connection = null;
PreparedStatement psInsert = null;
PreparedStatement psCheckUserExists = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/DTABASE_TABLE", "root", "");
psCheckUserExists = connection.prepareStatement("SELECT * FROM user_info WHERE email = ?");
psCheckUserExists.setString(1, email);
resultSet = psCheckUserExists.executeQuery();
if (resultSet.isBeforeFirst()) {
System.out.println("Email Already Exits");
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setContentText("You can not use this email");
alert.show();
} else {
psInsert = connection.prepareStatement("INSERT INTO user_info (username, email, password) VALUES (?, ?, ?)");
psInsert.setString(1, username);
psInsert.setString(2, email);
psInsert.setString(3, password);
psInsert.executeUpdate();
changeScene(event, "homePage.fxml", "Welcome ", username);
}
}
}
public static void logInUser(ActionEvent event, String email, String password) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/DATABASE_TABLE", "root", "");
preparedStatement = connection.prepareStatement("SELECT password FROM user_info WHERE email = ?");
preparedStatement.setString(1, email);
resultSet = preparedStatement.executeQuery();
if (!resultSet.isBeforeFirst()) {
System.out.println("User Not Found in the Database");
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setContentText("Provide credential are incorrect");
alert.show();
} else {
while (resultSet.next()) {
String retrievedPassword = resultSet.getString("password");
//String retrievedChannel = resultSet.getString("username");
if (retrievedPassword.equals(password)) {
changeScene(event, "homePage.fxml", "welcome ", email);
} else {
System.out.println("Password did not match");
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setContentText("The provide credentials are incorrect");
alert.show();
}
}
}
}
}
Two phases to sign-up
It sounds like you want to separate registration of a new user into two phases:
Initial sign-up/registration, essentially a request to be added as a user.
Verification by a human administrator allowing access, essentially granting (or denying) the request to be added as a user.
Record registration status
If that describes your core issue, you need to add another column to your users table. You need a reg_status_ column, non-null, where you track whether the user has initially applied, been granted access, been rejected in their request, or has been retired meaning no longer want or need to be a user. You could make this column a text type to get started. But in a serious deployment, I would make a custom type in the database so that only valid values could be inserted.
When the user first registers as a new user, you assign a default value indication initial application. Later when the administrator verifies the account, that administrator person alters the registration-status column to indicate approval or rejection. Later on, when the user quits, dies, or otherwise becomes ineligible, you change the registration-status to indicate the account is retired.
If the user attempts to login before the administrator has done their registration approval/rejection work, your code notices the registration-status still indicates initial registration still awaiting verification. Your user-interface should let the user know of that status, estimate how long to wait until access will be granted, and explain how to contact support staff if they suspect a problem has arisen.
None of this has anything to do with JavaFX in particular. Your user-interface needs to accommodate each of these registration-status states. JavaFX makes it easy for you to either morph a view or replace the view displayed to the user.
As you have seen on countless apps and web sites in your own experience, you know that a login screen should offer two paths, either (a) registration as a new user, or (b) an attempt at authentication. The result of the first is a form indicating their success at submitting a registration application. The result of the second is to display the usual starting point for using the content of your app.
Before coding, you should have all the views, and all the possible user-experience paths through those views, mapped out as a flowchart and/or storyboard.
By the way, your code has several other issues and problems. Some of these are noted in Comments on the Question. The most serious problem is directly writing a password — that should never be done.
Here is a method authenticate the user password. It verify the user email and password from the database.
public long authenticate(String email, String encodePassword) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (
Connection conn = DriverManager.getConnection("jdbc:connection", "adminusername","password");/* a) Database User Profile: root is who the user is b) Database user password */
Statement stmt = conn.createStatement();
) /* execute mysql queries */ {
String query = "Select id from User where email = '" + email + "' and password = '" + encodePassword + "'";
System.out.println("query: " + query);
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
// if the user id is there get it
return rs.getLong("id");
}
} catch (SQLException e) {
e.printStackTrace();
}
// if the user id not there return -1 (authority failed)
return -1;
}
To determine whether my lecture is right that I have hard-coded SQL queries values in my code
Your lecturer is trying to warn you about SQL injection.
SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database. It generally allows an attacker to view data that they are not normally able to retrieve. This might include data belonging to other users, or any other data that the application itself is able to access. In many cases, an attacker can modify or delete this data, causing persistent changes to the application's content or behavior.
The corresponding part in your code is the following
String query = "Select id from User where email = '" + email + "' and password = '" + encodePassword + "'";
If the query returns the id of a user, then the login is successful. Otherwise, it is rejected.
Here, an attacker can log in as any user without a password simply by using the SQL comment sequence -- to remove the password check from the WHERE clause of the query. For example, submitting the email some#email'-- and a blank password results in the following query:
SELECT id FROM users WHERE email = 'some#email'--' AND password = ''
This query returns the user whose email is some#email and successfully logs the attacker in as that user without checking the password.
So I have this working code/prepared statement that adds a username and password into a database, however I need to check if the username already exists in the code.
public void addUser(Connection conn, PreparedStatement pstmnt, String username, String password)
{
try
{
pstmnt = conn.prepareStatement("insert into users values (?,?,?)");
pstmnt.setInt(1, 0);
pstmnt.setString(2, username);
pstmnt.setString(3, password);
pstmnt.executeUpdate();
}
catch (SQLException e) { System.out.println("Error: " + e.getMessage()); }
System.out.println(username + " has been added");
}
Is there any simple way to do this?
You can add a unique constraint in the DB and handle the exception in addUSer accordingly
If there's no many duplicate key risk, you can just try and check the error code if it matches "dup key error" (Error ORA-00001).
Else you must lock the entire table, check for key existence, update and then commit (which release the lock)
I need to perform a task for a webpage application, that is to have a page to display the client's information by querying for them
via the client's session id (or some other method) and do a mySQL query into my membership database.
The sequence should be as follows:
1. client logs in
2. compare of client's password and membership database, if match, client will be able to access some pages
3. one of these accessible pages(mentioned in 2)in will contain a link which will then query for the client's information in membership database
4. queried rows(results) will be displayed in the webpage with proper css
just a disclaimer, I am a total beginner at java
Membership database
table's name = member
id | first name | last name | address | telephone number
I have already created and setup a jdbc connection to database:
public void init () throws ServletException {
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/membership","root","");
stmt = conn.createStatement();
} catch (ClassNotFoundException ex) { // for Class.forName()
ex.printStackTrace();
} catch (SQLException ex) { // for getConnection()
ex.printStackTrace();
}
}
String query = "SELECT * FROM member WHERE xxx ";
ResultSet rset = stmt.executeQuery(query);
my question is: how do i grab the necessary rows for my problem here? and how should i approach to solve this question?
many thanks for your advice
"my question is: how do i grab the necessary rows for my problem here?"
Use your ResultSet object (rset). Then retrieve any columns you need.
Something similar to this:
while (rs.next()) {
int ID = rs.getInt("id");
String fName = rs.getString("first_name");
String lName = rs.getString("last_name");
String address = rs.getString("address");
String phone = rs.getString("telephone_number");
}
First, I strongly recommend you have no spaces in your column names (eg use '_' instead).
What are your user credentials for logging in? I imagine it's username or email_address as well as password. Whatever the first part of that is (eg username) you could use that as the primary key on your member table. So after they've logged in, you already have username and that forms the 'where' clause in your SQL query. (If they log in with email_address, everything works the same, using that in place of username.)
So the steps are
Take username + password from user
Select count of rows matching that pair
If count == 1 then they're authenticated, otherwise reject
Select other fields matching username
Display to user
Don't store passwords plaintext, so whatever transform you apply for storing them, also apply that to the given password before doing #2. If you choose to have username not be a primary key, ensure you make it at least 'unique' via a constraint.
I have written a simple code to test login and password ,(login and password are given by the user) and then I compare them by login and password stored in the database. but the problem is the function return bad result (it browse all the rows even it is true at the first row)
this is the code:
public String LoginPasswordCheck(Connection con)
{
HashMap<String,String> mapLoginPWD = new HashMap<String,String> ();
String sqlLogin;
String checkaccess="true";
String log;
String pwd;
sqlLogin="select login ,password from profil_user;";
try{
st=(PreparedStatement) con.prepareStatement(sqlLogin);
ResultSet rs1 = st.executeQuery();
while(rs1.next())
{
log = rs1.getString("login");
pwd=rs1.getString("password");
mapLoginPWD.put(log, pwd);
}
Iterator iteratorkey = mapLoginPWD.keySet().iterator();
String myKey="";
String value="";
while(iteratorkey.hasNext())
{
myKey = (String) iteratorkey.next();
value= mapLoginPWD.get(myKey);
//login and password given by the user
if( !(this.login.equalsIgnoreCase(myKey)) && !(this.password.equalsIgnoreCase(value) )&& !(iteratorkey.hasNext()) )
{
checkaccess ="fail";
}
else
checkaccess ="success";
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return checkaccess;
}
I don't understand why you load a map of logins and passwords for each request. You could just load the password for the given login and if that fails, the login does not exist.
Futhermore, i wonder if you really want to ignore case on passwords and logins.
The code you present fails because you do not exit the loop when you find the matching login/password.
You should really refactor the code and eliminit the need for maps and looping. As i said, just look for the login that the user presents in your database.
There are several problems:
The SQL query returns a resultset for all users. You could specify a WHERE clause that would restrict this to 0 or 1 rows, depending on whether the user exists or not.
The code iterates through the results, and sets a flag. If the flag is set once, it can (and would be) reset on the next iteration. You should break out of the loop (so that once authentication is considered successful, it cannot be considered unsuccessful for the provided user ID and password). But if you were to fix the previous problem, then you don't need the loop in the first place.
It is unnecessary to store the contents of the resultset in a map. This is redundant, for the map is rebuilt on every query and discarded after execution.