I am trying to make a registration form. This code should stop the registration if there is a duplicate of username.
I actually copied this on this answer tried to modify it on my own so I could somehow learn how it works.
Here is my code:
private void register_user()
{
con.Open();
bool exist = false;
// Command that checks if username exist
cmd = new SqlCommand(#"SELECT COUNT(*) FROM users1 WHERE Username = '#username'", con);
cmd.Parameters.AddWithValue("#username", txtRegUsername.Text);
exist = (int)cmd.ExecuteScalar() > 0;
// If user exist gives error
if (exist == true)
lblResults.Text = "Username already exist!";
else
{
cmd = new SqlCommand(#"INSERT INTO users1 (Fname, Lname, Mname,
Username, Password, email, user_type)
VALUES (#first_name, #last_name, #middle_name,
#username, #password, #email, #user_type)", con);
cmd.Parameters.AddWithValue("#first_name", txtFname.Text);
cmd.Parameters.AddWithValue("#last_name", txtLname.Text);
cmd.Parameters.AddWithValue("#middle_name", txtMi.Text);
cmd.Parameters.AddWithValue("#username", txtRegUsername.Text);
cmd.Parameters.AddWithValue("#password", txtRegPassword.Text);
cmd.Parameters.AddWithValue("#email", txtEmail.Text);
cmd.Parameters.AddWithValue("#user_type", "user");
cmd.ExecuteNonQuery();
}
con.Close();
}
My problem is that my code allows the registration of Username which already exist. Overall its working.
Instead of
SELECT COUNT(*) FROM users1 WHERE Username = '#username'
use
SELECT COUNT(*) FROM users1 WHERE Username = #username
Otherwise that's not a parameter but a static value for Username.
Side note: I would not count records if I want to know if something exists.
This is more efficient:
SELECT
CASE WHEN EXISTS(SELECT 1 FROM users1 WHERE Username = #username)
THEN 1
ELSE 0
END AS DoesUserExist
Try the below code.. Hope this will help you.
cmd = new SqlCommand(#"SELECT COUNT(*) FROM users1 WHERE upper(Username) = upper(#username)", con);
exist is false then you return the value of the SelectCount.
I would do something as
If((int)cmd.ExecuteScalar() > 0)
{
exist=true;
}
Also remove the ' ' from #username on the query as others said.
Related
How do I modify this registration code so it checks if email entered already exists in the database?
I already have a query written for it, but I don't know how to implement it
[HttpPost("Register")]
public async Task<ActionResult<User>> Register(UserDto request, Guid guid)
{
string query = #"
insert into dbo.Users(UserID,Name,Email,PasswordHash,PasswordSalt)
values (#UserID,#Name,#Email,#PasswordHash,#PasswordSalt)
";
string emailValidationQuery = #"SELECT * FROM dbo.Users WHERE Email = #Email";
CreatePasswordHash(request.Password, out byte[] passwordHash, out byte[] passwordSalt);
string psw = PasswordHash(request.Password);
Guid guid1 = Guid.NewGuid();
guid = guid1;
user.UserID = guid;
user.Username = request.Username;
user.Email = request.Email;
user.PasswordHash = Encoding.UTF8.GetBytes(psw);
user.PasswordSalt = passwordSalt;
DataTable table = new DataTable();
string sqlDataSource = _configuration.GetConnectionString("ContactAppCon");
SqlDataReader myReader;
using (SqlConnection myCon = new SqlConnection(sqlDataSource))
{
myCon.Open();
using (SqlCommand myCommand = new SqlCommand(query, myCon))
{
myCommand.Parameters.AddWithValue("#UserID", Guid.NewGuid());
myCommand.Parameters.AddWithValue("#Name", request.Username);
myCommand.Parameters.AddWithValue("#Email", request.Email);
myCommand.Parameters.AddWithValue("#PasswordHash", psw);
myCommand.Parameters.AddWithValue("#PasswordSalt", passwordSalt);
myReader = myCommand.ExecuteReader();
table.Load(myReader);
myReader.Close();
myCon.Close();
}
}
return Ok(user);
}
Try something like below (open and dispose the connections properly)
string emailValidationQuery = #"SELECT Count(*) FROM dbo.Users WHERE Email = #Email";
....
using SqlCommand command = new SqlCommand(emailValidationQuery, myCon);
int count = (Int32) command.ExecuteScalar();
if(count > 0)
return new User() // or whatever you required
Why not a single statement:
INSER INTO dbo.Users (UserID, Name, Email, ...)
VALUES (#UserID, #Name, #Email, ...)
WHERE NOT EXISTS
(
SELECT 0
FROM dbo.Users WITH (SERIALIZABLE, UPDLOCK)
WHERE Email = #Email
);
If this affects 0 rows (you can check with ##ROWCOUNT), then the e-mail already existed (and maybe you should run an update instead in that case, but it's not clear from the question) or the insert failed for some other reason (which you can check with simple try/catch patterns).
And you can prevent race conditions and avoid costly exceptions by doing it a little differently:
BEGIN TRANSACTION;
IF NOT EXISTS
(
SELECT 0 FROM dbo.Users WITH (SERIALIZABLE, UPDLOCK)
WHERE Email = #Email
)
BEGIN
INSERT ...
END
ELSE
BEGIN
-- UPDATE? RAISERROR? Again requirements aren't clear.
END
COMMIT TRANSACTION;
Don't go for simple or expensive when correct and more efficient are better.
I started to learn ASP.NET. I create a register system, and when I try to check if the username or email already exists in the database, it's not checked and creates the user even when you have it already.
try
{
conn.Open();
bool exists = false;
string checkuser = "SELECT count(*) FROM accounts WHERE username='" + username.Text + "'";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("username", username.Text);
exists = (int)cmd2.ExecuteScalar() > 0;
if (exists)
{
Response.Write("User already exists");
}
string command = "INSERT INTO accounts (username, email, password) VALUES (#username, #email, #password)";
SqlCommand cmd = new SqlCommand(command, conn);
cmd.Parameters.AddWithValue("#username", username.Text);
cmd.Parameters.AddWithValue("#email", email.Text);
cmd.Parameters.AddWithValue("#password", password.Text);
cmd.ExecuteNonQuery();
}
catch(Exception)
{
label_msg.Visible = true;
label_msg.Text = "Something went wrong....";
throw;
}
finally
{
Response.Redirect("/layout.aspx");
conn.Close();
}
Thanks !
string checkuser = "if exists (select 1 from accounts where username=#username) select 1 else select 0 end";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("#username", username.Text);
bool exists = (int)cmd2.ExecuteScalar() > 0;
Having SQL Server check for the existence of matches will stop at the first match instead of potentially returning a set of matches and then it is simply returning a value accordingly. This will minimize data transferred between the server and your software plus avoid performing a count when we really just care if there are any matches.
whenever you want to find TRUE/FALSE value or counting the no records always use COUNT(1).
bool exists = false;
string checkuser = "SELECT count(*) FROM accounts WHERE username=#username;";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("#username", username.Text);
object result = cmd2.ExecuteScalar();
if (result != null)
exists = (Convert.ToInt32(result) == 1) ? true : exists;
if (exists)
{
Response.Write("User already exists");
}
Check if user Exist already
int exists = 0;
string checkuser = "SELECT count(*) FROM accounts WHERE username='" +username.Text + "'";
SqlCommand cmd2 = new SqlCommand(checkuser, conn);
cmd2.Parameters.AddWithValue("username", username.Text);
exists = (int)cmd2.ExecuteScalar();
if (exists>0)
{
Response.Write("User already exists");
}
I need to check in C# if the user has a particular role from the database and in windows form my login code is
SqlCommand cmd = new SqlCommand("SELECT UserName,Password FROM EMP_Info WHERE UserName='" + txt_Username.Text + "' and Password='" + txt_password.Text + "'", sqlcon);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0)
{
Cursor.Current = Cursors.WaitCursor;
// I need to make if here to check the role if the user is admin or not
// if admin do something
MessageBox.Show("Welcome " + txt_Username.Text);
}
else
{
MessageBox.Show("The Username or Password you entered is incorrect. Please try again");
sqlcon.Close();
}
My database code
create proc Check_role
#EMP_Role varchar (10),
as
begin
if (exists(select EMP_Role from EMP_Info where EMP_Role ='Admin' ))
return 1
else
return 2
end
so i need to solve this problem
To avoid SQL Inject Attack use parametrized query something like this.....
SqlCommand cmd = new SqlCommand("SELECT [UserName] , [Password] FROM EMP_Info WHERE [UserName] = #UserName and [Password] = #Password", sqlcon);
cmd.Parameters.AddWithValue("#UserName" , txt_Username.Text);
cmd.Parameters.AddWithValue("#Password" , txt_password.Text);
//rest of the code
Anyway I would create a procedure to make just one call to database to verify the user logging in. A stored procedure can look something like ....
CREATE PROCEDURE Check_role
#UserName VARCHAR(100)
,#Password VARCHAR(100)
,#IsValid INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Emp_Role VARCHAR(10);
DECLARE #UserName_check VARCHAR(10);
DECLARE #PassWord_check VARCHAR(10);
SELECT TOP 1 #Emp_Role = EMP_Role
,#UserName_check = [UserName]
,#PassWord_check = [Password]
FROM EMP_Info
WHERE [UserName] = #UserName
AND [Password] = #Password
IF ((#UserName_check = #UserName) AND (#PassWord_check = #Password))
BEGIN
SET #IsValid = 1;
IF (#Emp_Role = 'Admin')
BEGIN
SET #IsValid = 2;
END
END
ELSE
BEGIN
SET #IsValid = 0;
END
END
C# Code
using(SqlConnection Sqlcon = new SqlConnection(ConnectionString))
{
SqlCommand cmd = new SqlCommand("dbo.Check_role", sqlcon);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserName", txt_Username.Text);
cmd.Parameters.AddWithValue("#Password", txt_password.Text);
cmd.Parameters.Add("#IsValid", SqlDbType.Int);
cmd.Parameters["#IsValid"].Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
string LoginStatus = cmd.Parameters["#IsValid"].Value.ToString();
if (LoginStatus == 1 || LoginStatus == 2)
{
if(LoginStatus == 2)
{
// if a user is admin do stuff here
}
else
{
// if a user is NOT admin do stuff here
}
MessageBox.Show("Welcome " + txt_Username.Text);
}
else
{
MessageBox.Show("The Username or Password you entered is incorrect. Please try again");
}
}
I've written this registration form which adds data to my SQL Server database. What I want is an exception when the user enters a username that is already in the database.
protected void Button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection conn2 = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString);
conn2.Open();
string CheckUser = "select Username from UserData where Username like #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn2);
com2.Parameters.AddWithValue("#Username", "'%"+ UsernameTextBox.Text +"%'");
com2.ExecuteNonQuery();
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
conn2.Close();
if (IsMatch == 0)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString);
conn.Open();
string InsertQuery = "insert into UserData (Username, Email, Password, Country) values (#Username, #Email, #Password, #Country)";
SqlCommand com = new SqlCommand(InsertQuery, conn);
com.Parameters.AddWithValue("#Username", UsernameTextBox.Text);
com.Parameters.AddWithValue("#Email", EmailTextBox.Text);
com.Parameters.AddWithValue("#Password", PasswordTextBox.Text);
com.Parameters.AddWithValue("#Country", CountryDropDownList.SelectedItem.ToString());
com.ExecuteNonQuery();
Response.Redirect("Manager.aspx");
conn.Close();
}
else
{
Response.Write("User Already Exists!");
}
}
catch (Exception ex)
{
Response.Write(Convert.ToString(ex));
}
}
When I run it, I get an exception on the following line:
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
Blam's second solution works, but the IsMatch can be simplified a bit by casting to int instead of going to string and parsing.
This should also be handled at the database level. Set a primary key on your username column:
ALTER TABLE UserData ADD CONSTRAINT
PK_UserData PRIMARY KEY CLUSTERED (Username)
If you do it this way, then you don't even have to check for duplicates explicitly, you can just try to create the user and handle the exception if it fails:
try
{
using (var conn = new SqlConnection((ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString)))
{
conn.Open();
#if DOUBLE_CHECK
string CheckUser = "select count(*) from UserData where Username = #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn);
com2.Parameters.AddWithValue("#Username", UsernameTextBox.Text);
if ((int)com2.ExecuteScalar() > 0)
{
Response.Write("User already exists");
return;
}
#endif
string InsertQuerry = "insert into UserData (Username,Email,Password,Country) values (#Username,#Email,#Password,#Country)";
SqlCommand com = new SqlCommand(InsertQuerry, conn);
com.Parameters.AddWithValue("#Username", UsernameTextBox.Text);
com.Parameters.AddWithValue("#Email", EmailTextBox.Text);
com.Parameters.AddWithValue("#Password", PasswordTextBox.Text);
com.Parameters.AddWithValue("#Country", CountryDropDownList.SelectedItem.ToString());
com.ExecuteNonQuery();
Response.Redirect("Manager.aspx");
}
}
catch (SqlException se)
{
if (se.Errors.OfType<SqlError>().Any(e => e.Number == 2627))
{
Response.Write("User already exists");
}
else
{
Response.Write(se.ToString());
}
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
If you handle the exception this way, the #if DOUBLE_CHECK section is redundant and can be removed. An attempt to add duplicate name will cause a SQL error and exception, and this will detect and handle the "duplicate key" error.
Two unrelated notes on your code:
Response.Redirect() will abort the current thread and your conn.Close() will not be called. Use a using() to ensure it's called.
Storing a password in the database as plain text is a disaster waiting to happen. PLEASE take a look at Best way to store password in database for some ideas about how to do this correctly
That won't return an integer
string CheckUser = "select count(*) from UserData where Username like #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn2);
com2.Parameters.AddWithValue("#Username", "'%"+ UsernameTextBox.Text +"%'");
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
And you don't need to use two different connections.
Just use one and close it in a Finally.
string CheckUser = "select count(*) from UserData where Username = #Username";
SqlCommand com2 = new SqlCommand(CheckUser, conn2);
com2.Parameters.AddWithValue("#Username", UsernameTextBox.Text );
int IsMatch = Convert.ToInt32(com2.ExecuteScalar().ToString());
This returns 0 or 1. This should fix your issue. Looks like you need to return an int type. Or you could change it to bool if you want. Either way, this sql statement should help! :)
select
isnull(convert(bit,(select top 1 case
when username != '' then 1
else 0 end
from UserData
where username like #Username)),0)
How do I fix the IF statement so when the user tries to sign up using an already existing username. Currently my program will not accept the data entered if the username is already existing, but it still proceeds to the next page (even though the data is not saved in the database). What I need to know is how to eliminate the problem so when the user does enter a "username" that exists it'll just give the message box for the error and not move to the next page.
Thanks!
private void btnSignupNew_Click(object sender, EventArgs e)
{
if (txtUsername.Text == "")
{
errorUsername.SetError(txtUsername, "Enter A Username");
}
else if (txtPassword.Text == "")
{
errorPassword.SetError(txtPassword, "Enter A Valid Password");
}
else
{
using (SqlConnection con = new SqlConnection("Data Source=etc"))
{
con.Open();
bool exists = false;
// create a command to check if the username exists
using (SqlCommand cmd = new SqlCommand("select count(*) from [User] where UserName = #UserName", con))
{
cmd.Parameters.AddWithValue("UserName", txtUsername.Text);
exists = (int)cmd.ExecuteScalar() > 0;
}
// if exists, show a message error
if (exists)
{
MessageBox.Show("Username: " + txtUsername.Text + " already Exists");
//errorPassword.SetError(txtUsername, "This username has been using by another user.");
}
else
{
// does not exists, so, persist the user
using (SqlCommand cmd = new SqlCommand("INSERT INTO [User] values (#Forename, #Surname, #Username, #Password)", con))
{
cmd.Parameters.AddWithValue("Forename", txtForename.Text);
cmd.Parameters.AddWithValue("Surname", txtSurname.Text);
cmd.Parameters.AddWithValue("UserName", txtUsername.Text);
cmd.Parameters.AddWithValue("Password", txtPassword.Text);
cmd.ExecuteNonQuery();
}
}
con.Close();
MessageBox.Show("Sucessfully Signed Up");
Form1 signin = new Form1();
signin.Show();
this.Close();
}
}
}
}
Your code is always going to close the form and launch the login form, regardless of whether the username already existed or not, because the logic to do the login form is executed after your test for uniqueness. It should only happen when the test for uniqueness suceeds.
Change your logic to look like this:
// if exists, show a message error
if (exists)
{
MessageBox.Show("Username: " + txtUsername.Text + " already Exists");
//errorPassword.SetError(txtUsername, "This username has been using by another user.");
}
else
{
// does not exists, so, persist the user
using (SqlCommand cmd = new SqlCommand("INSERT INTO [User] values (#Forename, #Surname, #Username, #Password)", con))
{
cmd.Parameters.AddWithValue("#Forename", txtForename.Text);
cmd.Parameters.AddWithValue("#Surname", txtSurname.Text);
cmd.Parameters.AddWithValue("#UserName", txtUsername.Text);
cmd.Parameters.AddWithValue("#Password", txtPassword.Text);
cmd.ExecuteNonQuery();
}
MessageBox.Show("Sucessfully Signed Up");
Form1 signin = new Form1();
signin.Show();
this.Close();
}
con.Close();
Change your Parameters to look like the following as well
I would also recommend adding some sort of Validation if necessary to the edit boxes in case someone adds improper values to prevent from any SQL Injectection personally I would create Property values for the Edit boxes and pass in the Property Value(s). just a suggestion
First problem in your code that stood out to me was the following line
cmd.Parameters.AddWithValue("UserName", txtUsername.Text);
should be
cmd.Parameters.AddWithValue("#UserName", txtUsername.Text);
// if exists, show a message error
if (exists)
{
MessageBox.Show("Username: " + txtUsername.Text + " already Exists");
//errorPassword.SetError(txtUsername, "This username has been using by another user.");
}
else
{
// does not exists, so, persist the user
using (SqlCommand cmd = new SqlCommand("INSERT INTO [User] values (#Forename, #Surname, #Username, #Password)", con))
{
cmd.Parameters.AddWithValue("#Forename", txtForename.Text);
cmd.Parameters.AddWithValue("#Surname", txtSurname.Text);
cmd.Parameters.AddWithValue("#UserName", txtUsername.Text);
cmd.Parameters.AddWithValue("#Password", txtPassword.Text);
cmd.ExecuteNonQuery();
}
MessageBox.Show("Sucessfully Signed Up");
Form1 signin = new Form1();
signin.Show();
this.Close();
}
con.Close();