Login Stored Procedure - SQL Server - sql

I have a stored procedure for login. There are three parameters:
i) Email
ii) Password
iii) IsActive.
I want to check various aspects and return a bit value for each case.
I tried:
CREATE PROCEDURE [dbo].[SP_Login]
#Email VARCHAR(100),
#Password VARCHAR(50),
#ReturnValue INT
AS
BEGIN
-- No User
IF NOT EXISTS (Select * From AdminAccount Where Email=#Email and Password = #Password)
BEGIN
SET #ReturnValue = 0
END
-- Active User
ELSE IF EXISTS (Select * From AdminAccount Where Email=#Email and Password = #Password and IsActive='1')
BEGIN
SET #ReturnValue = 1
END
-- Not Active user
ELSE IF EXISTS (Select * From AdminAccount Where Email=#Email and Password = #Password and IsActive='0')
BEGIN
SET #ReturnValue = 2
END
-- Email Not Exist
ELSE IF NOT EXISTS (Select * From AdminAccount Where Email=#Email)
BEGIN
SET #ReturnValue = 3
END
-- Password Not Match
ELSE IF EXISTS (Select * From AdminAccount Where Email=#Email)
BEGIN
SET #ReturnValue = 4
END
END
Now the issue is it uses various SELECT Queries.
Is there any way to minimize or Optimize the code without losing meaning.

Try this
declare #AdminAccount table (Email varchar(100), Pass varchar(50), IsActive bit)
insert into #AdminAccount
values ('mail1#m.com', 'abc', 1), ('mail2#m.com', '123', 0)
--Testing values
declare #Email VARCHAR(100) = 'mail2#m.com',
#Password VARCHAR(50) = '123',
#ReturnValue tinyint
--Temporary table: It avoid us to query the table many times
declare #userData table (Email varchar(100), Pass VARCHAR(50), IsActive bit)
if exists ( select top 1 1 from #AdminAccount where Email = #Email )
insert into #userData
select Email, Pass, IsActive
from #AdminAccount
where Email = #Email
else
begin
if not exists ( select top 1 1 from #AdminAccount where Email = #Email and Pass = #Password )
set #ReturnValue = 0
else
set #ReturnValue = 3 --it will never return this value (3)
end
select #ReturnValue =
case
when #Email = Email and #Password = Pass and IsActive = 1 then 1
when #Email = Email and #Password = Pass and IsActive = 0 then 2
else 4
end
from #userData
select #ReturnValue as RV

Try this:
IF EXISTS (SELECT * FROM AdminAccount WHERE Email=#Email)
BEGIN
SELECT #ReturnValue =
CASE WHEN Password = #Password AND IsActive='1' THEN 1 -- Password match, Active User
WHEN Password = #Password AND IsActive='0' THEN 2 -- Password match, Inactive User
WHEN Password <> #Password AND IsActive='1' THEN 3 -- Active User, Password does not match
WHEN Password <> #Password AND IsActive='0' THEN 4 -- Inactive User, Password does not match
ELSE 0 -- Details (Email and Password) do not match
END
FROM AdminAccount WHERE Email=#Email
END
ELSE IF NOT EXISTS (SELECT * FROM AdminAccount WHERE Email=#Email)
BEGIN
SET #ReturnValue = 0
END

Since the question isn't about how to store passwords in a database, I will not be addressing that in this answer.
The first thing I must point out is that your procedure will never return the value 3. If the Email parameter does not match an account, your condition for returning 0 will always be met before the condition for returning 3 is evaluated. For that reason I've excluded it in this answer.
If your goal is to avoid multiple queries inside your stored procedure (a good idea), you can accomplish the same logic by using a single query and local variables. Here is a proof of concept using Microsoft SQL Server 2014.
CREATE TABLE AdminAccount (
Email VARCHAR(100),
Password VARCHAR(50),
IsActive BIT
)
INSERT INTO AdminAccount (Email,Password,IsActive) VALUES ('test#test.com','password',1)
INSERT INTO AdminAccount (Email,Password,IsActive) VALUES ('test2#test.com','password2',0)
INSERT INTO AdminAccount (Email,Password,IsActive) VALUES ('test3#test.com','password3',0)
SELECT * FROM AdminAccount
DECLARE #EmailParam VARCHAR(100) = 'test2#test.com'
DECLARE #PasswordParam VARCHAR(50) = 'password'
DECLARE #ReturnValue INT
DECLARE #LocalEmail VARCHAR(100)
DECLARE #LocalPassword VARCHAR(50)
DECLARE #LocalActive BIT
SELECT #LocalEmail = Email, #LocalPassword = Password, #LocalActive = IsActive FROM AdminAccount WHERE Email=#EmailParam
SET #ReturnValue =
CASE
WHEN #LocalEmail IS NULL AND #LocalPassword IS NULL
THEN 0 -- No User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 1
THEN 1 -- Active User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 0
THEN 2 -- Inactive User
WHEN #LocalPassword <> #PasswordParam
THEN 4 -- Invalid Password
END
SELECT #ReturnValue
Here is the updated stored procedure using the local variable logic above.
CREATE PROCEDURE [dbo].[SP_Login]
#Email VARCHAR(100),
#Password VARCHAR(50),
#ReturnValue INT OUTPUT
AS
BEGIN
-- Declare local variables to avoid multiple queries
DECLARE #LocalEmail VARCHAR(100)
DECLARE #LocalPassword VARCHAR(50)
DECLARE #LocalActive BIT
-- Gather data
SELECT #LocalEmail = Email, #LocalPassword = Password, #LocalActive = IsActive FROM AdminAccount WHERE Email=#EmailParam
SET #ReturnValue =
CASE
WHEN #LocalEmail IS NULL AND #LocalPassword IS NULL
THEN 0 -- No User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 1
THEN 1 -- Active User
WHEN #LocalPassword = #PasswordParam AND #LocalActive = 0
THEN 2 -- Inactive User
WHEN #LocalPassword <> #PasswordParam
THEN 4 -- Invalid Password
END
END

Related

Return value based on count from SQL Server Stored Procedure

I have the following SQL Server Stored Procedure which validates a password.
ALTER PROC [dbo].[spValidatePassword]
#UserId uniqueidentifier,
#Password NVARCHAR(255)
AS
BEGIN
DECLARE #PasswordHash NVARCHAR(255) = HASHBYTES('SHA2_512', (SELECT #Password + CAST((SELECT p.PasswordSalt FROM Passwords p WHERE p.UserId = #UserId) AS NVARCHAR(255))))
SELECT COUNT(*)
from Passwords
WHERE UserId = #UserId
AND [Password] = #PasswordHash
--return 1 if valid password
--return 0 if not valid
END
How can I return 1 from the stored procedure if the count is greater than zero, and zero otherwise?
Try this query, will return 1 if there is a result, else 0
SELECT (CASE WHEN COUNT(*) > 1 THEN 1 ELSE 0 END)
FROM Passwords
WHERE UserId = #UserId
AND [Password] = #PasswordHash
ALTER PROC [dbo].[spValidatePassword]
#UserId uniqueidentifier,
#Password NVARCHAR(255)
AS
BEGIN
DECLARE #PasswordHash NVARCHAR(255) = HASHBYTES('SHA2_512', (SELECT #Password + CAST((SELECT p.PasswordSalt FROM Passwords p WHERE p.UserId = #UserId) AS NVARCHAR(255))))
SELECT
CASE WHEN EXISTS (
SELECT *
from Passwords
WHERE UserId = #UserId
AND [Password] = #PasswordHash
)
THEN 1
ELSE 0
END
--return 1 if valid password
--return 0 if not valid
END
But consider using some other authentication model like OAuth or Office 365 logins rather than reinventing the wheel
IF (SELECT COUNT(UserId) from Passwords WHERE UserId = #UserId AND [Password] = #PasswordHash) > 0
begin
return 1;
End
ELse
begin
return 0;
end
this query will return the required result
IF EXISTS (
SELECT *
from Passwords
WHERE UserId = #UserId
AND [Password] = #PasswordHash
)
RETURN 1;
ELSE
RETURN 0;
You can also use OUTPUT Type stored procedure to get a scalar (in your case either 1 or 0) result as:
ALTER PROC [dbo].[spValidatePassword]
#UserId uniqueidentifier,
#Password NVARCHAR(255),
#result TINYINT OUTPUT
AS
BEGIN
DECLARE #PasswordHash NVARCHAR(255) = HASHBYTES('SHA2_512', (SELECT #Password + CAST((SELECT p.PasswordSalt FROM Passwords p WHERE p.UserId = #UserId) AS NVARCHAR(255))))
SELECT #result = COUNT(*)
from Passwords
WHERE UserId = #UserId
AND [Password] = #PasswordHash
END
You can execute this proc as:
DECLARE #output TINYINT
EXEC [dbo].[spValidatePassword] #UserId= 'any user id',#Password = 'any password',#result = #output OUTPUT
PRINT #output

Stored Procedure does not insert data

I am going nuts with a SQL Server stored procedure, it is supposed to register an user into the database (If the user does not already exists). But, after successfully executing the procedure, no data is inserted into the Users table.
If I run the insert statement directly, it works.
Below is the full procedure code, before you ask me, the database is empty.
--USERS
CREATE PROCEDURE [dbo].[RegisterUser]
#NAME VARCHAR(255),
#PHONENUMBER VARCHAR(255),
#STATUS INT OUT,
#REMAININGDAYS INT OUT
AS
BEGIN
SET NOCOUNT ON;
UPDATE Users WITH (serializable)
SET Name = #NAME
WHERE PhoneNumber LIKE #PHONENUMBER
SET #REMAININGDAYS = 0
IF ##rowcount = 0
BEGIN
INSERT INTO Users (Name, PhoneNumber, RegisterDate)
VALUES (#NAME, #PHONENUMBER, GETDATE())
SET #STATUS = 0
SET #REMAININGDAYS = 40
END
ELSE
BEGIN
DECLARE #USERID BIGINT
DECLARE #EXP DATETIME
SELECT TOP 1
#USERID = USERID
FROM USERS
WHERE PhoneNumber LIKE #PHONENUMBER
SELECT TOP 1
#EXP = DATEADD(day, DAYS, REGISTERDATE)
FROM SUBSCRIPTIONS
WHERE USERID = #USERID
ORDER BY [REGISTERDATE]
IF #EXP IS NULL
BEGIN
SELECT TOP 1
#EXP = DATEADD(day, 40, REGISTERDATE)
FROM USERS
WHERE USERID = #USERID
IF GETDATE() < #EXP
BEGIN
SET #STATUS = 0
SET #REMAININGDAYS = DATEDIFF(day, GETDATE(), #EXP)
END
ELSE
BEGIN
SET #STATUS = -1
END
END
ELSE
BEGIN
IF GETDATE() < #EXP
SET #STATUS = 1
ELSE
SET #STATUS = -1
END
END
END
I call it passing all parameters.
Thank you!
Statements that make a simple assignment always set the ##ROWCOUNT value to 1. ##ROWCOUNT (Transact-SQL)
So
DECLARE #i int
SET #i = 0
PRINT ##ROWCOUNT
prints 1.
DECLARE #RC INT
UPDATE Users WITH (serializable) SET Name = #NAME
WHERE PhoneNumber LIKE #PHONENUMBER
SET #RC = ##ROWCOUNT
SET #REMAININGDAYS = 0
IF ##RC = 0
BEGIN
INSERT INTO Users <etc...>
Or move SET #REMAININGDAYS = 0 above the update statement so nothing between the update and the test of ##ROWCOUNT.

Considering empty string to null in query

I am using sql server R2. I have a stored procedure in which I am passing two paramaters as #username varchar(100) and #password varchar(100).
Now, when I create user from my application first time, the password will be NULL.
I want to make a query which return record for matching username and password. The problem is code is passing empty string to stored procedure. I want something that consider or convert empty string to NULL automatically. I already have solution for this using if condition but I want to use single query, not if condition.
EDIT :
Its a simple stored procedure :
CREATE PROCEDURE [dbo].[Pro_TblP]
(
#userName varchar(100),
#password varchar(100)
)
AS
BEGIN
IF (#password ='')
BEGIN
SELECT * FROM TblP
WHERE username = #userName AND password IS NULL AND IsDeleted = 0
END
ELSE
BEGIN
SELECT * FROM TblP
WHERE username = #userName AND password = #password AND IsDeleted = 0
END
END
GO
I want to combine the query in single representation. Don't want the if condition.
CREATE PROCEDURE [dbo].[Pro_TblP]
(
#userName varchar(100),
#password varchar(100)
)
AS
BEGIN
SELECT * FROM TblP
WHERE username = #userName AND COALESCE(password,'') = #password AND IsDeleted = 0
END
GO
SQL Fiddle
Try this
alter PROCEDURE [dbo].[Pro_TblP]
(
#userName varchar(100),
#password varchar(100)=''
)
AS
BEGIN
BEGIN
SELECT * FROM TblP
WHERE username = #userName AND IsNull(password,'')=#password AND IsDeleted = 0
END
END
Try below code :
when #password is empty string OR null it will return all values. when you pass a string in #password variable it will then filter it.
CREATE PROCEDURE [dbo].[Pro_TblP]
(
#userName varchar(100),
#password varchar(100)
)
AS
BEGIN
SELECT * FROM TblP
WHERE username = #userName AND IsDeleted = 0
And (password = #password OR isnull(#password,'') = '')
END
SELECT *
FROM TblP
WHERE username = #userName AND
IsDeleted = 0 AND
(
password = #password OR
password IS NULL AND #password = ''
)

need two return value from a stored procedure in c#

I want to call a Stored Procedure which takes two parameters(username & password) and returns two values of type int( 'result' and 'group' ) 'result' for checking whether the user is valid or not and 'group' simply shows the group number of customers
there are three type of groups
group#1 : admin users
group#2 : custom users
grpup#3 : special users
below is my current code which only returns result
ALTER PROCEDURE [dbo].[suserpass]
#username Varchar(50),
#password varchar(50),
#result int OUTPUT,
#group int OUTPUT
AS
IF EXISTS (select [user] from [userpassTable] where [user] = #username and [pass]=#password)
set #result=1
else
set #result=0
thanks
you need do soemthing as below you need to set both output variable that will do your task .....
ALTER PROCEDURE [dbo].[suserpass]
#username Varchar(50),
#password varchar(50),
#result int OUTPUT,
#group int OUTPUT
AS
IF EXISTS (select [user] from [userpassTable] where [user] = #username and [pass]=#password)
begin
select #result=1
select #group = usergroup from [userpassTable] where [user] = #username and [pass]=#password
end
else
begin
select #result=0
select #group=0
end
I guess that, conceptually, you’re looking for something like this (haven’t tested the code):
ALTER PROCEDURE [dbo].[suserpass]
#username Varchar(50),
#password varchar(50),
#result int OUTPUT,
#group int OUTPUT
AS
IF EXISTS (select [user] from [userpassTable] where [user] = #username and [pass] = #password)
BEGIN
set #result = 1
set #group = (select (top 1) [groupType] from [userGroupTable] where [user] = #username)
END
else
set #result=0
Set both output parameters.
You can do it like this:
IF EXISTS (SELECT [user] FROM [userpassTable]
WHERE [user] = #username AND [pass] = #password)
BEGIN
SELECT #result=1 , #group = group
FROM [userpassTable]
WHERE [user] = #username
END
else
BEGIN
SELECT #result=0 , #group = 0 -- group 0 doesn't exist, used as user does exist
END
I have added BEGIN/END blocks for readability and to allow more than one statement.
In your C# both #result and #group should be set to output parameters.

Easiest way to validate user in stored procedure?

I need a stored procedure that can check to see if, on a login attempt, whether or not they are a valid user by sending the login and password to see if they match in the database. Is there a simple way to do this?
Without more information the best I can offer for the moment is:
CREATE STORED PROCEDURE CheckPassword
#username VARCHAR(20),
#password varchar(20)
AS
BEGIN
SET NOCOUNT ON
IF EXISTS(SELECT * FROM usertable WHERE username = #username AND password = #password)
SELECT 'true' AS UserExists
ELSE
SELECT 'false' AS UserExists
END
Query amended based on your response - this will return the string 'true' or 'false' you could replace them with bit values 1 and 0 respectively if you prefer.
This might help:
CREATE PROCEDURE CheckPassword
#username VARCHAR(20),
#password varchar(20)
AS
BEGIN
SET NOCOUNT ON
SELECT CASE WHEN EXISTS(SELECT NULL FROM usertable WHERE userName=#username AND password=#password)
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END
END
Create proc usp_ValidateStoreKeeperLogin
#SalesmanCode VARCHAR(50)
,#LogisticUserCode VARCHAR(50)
,#LogisticUserPassword VARCHAR(50)
AS
BEGIN
if EXISTS(select 1 from tblUser where Code=#LogisticUserCode And [password]=#LogisticUserPassword )
SELECT '1234' SalesmanCode,'12345' LogisticUserCode,'12346' DistributorCode,1 as ReturnValue,'Success' AS Msg from tblUser
select 'INVALID USER CODE' AS Msg ,-1 as ReturnValue
END
go
CREATE PROC usp_ValidateUser
( #userName VARCHAR(50),
#password VARCHAR(50)
)
AS
begin
declare #credentials TABLE(
username varchar(50),
userPassword varchar(50)
)
SELECT null,
CASE WHEN NombreUsuario = 'korn' and PasswordUsuario = HASHBYTES('sha1', '1234') THEN cast(1 as bit)
ELSE cast(0 as bit) end as TieneAcceso
FROM Usuarios;
end
Create procedure validate_data
#username varchar(20),
#password varchar(20)
As
Begin
If exists (select * from employee where username=#username and password=#password)
Raiserror('Exists'16,1)
Else
Raiserror('Not Exists'16,1)
End
Here I take employee as table and username and password has the employee tables .