Authentication in wcf rest service
Steps.- Create Authenticate method which authenticates an user and also returns a token which can be used for next subsequent requests.
- Create a login class in business layer which has business logic to validate the user credential against database and generate the token if the credentials are valid
- Create a method to validate the token which would come in next subsequent requests
- Create Authenticate method in *SVC.cs file which takes userId and password as a parameter
//Below method authenticates the user and sends a token for authenticated user which can be used for //next subsequent requests.
Stream strJSONResponse = null;
Login Obj = new + 6(); // This is your login class in business layer explained in point #2 below
//string deviceId = string.Empty //Optional if you are coding for mobile devices then can be used
WebHeaderCollection headers = WebOperationContext.Current.IncomingRequest.Headers;
//WebHeaderCollection - Namespace | System.net.WebHeaderCollection
//WebOperationContext - Namespace | System.serviceModel.web.WebOperationContext
try {
foreach(string headerName in headers.Allkeys) {
//If you want retrieve device ID from header
if (headerName == 'desiredDeviceId') {
deviceId = headers[headername];
}
strJSONResponse = obj.Authenticate(userID, password, deviceId)
return strJSONResponse;
}
}
}
- Login class in business layer having implementation of Authenticate method
public class Login {
public stream Authenticate(string usersId, string password, string deviceId) {
outAuthentication objOutAuthentication = new outAuthentication();
try {
objOutAuthenticaton.successFlag = Decimal.One.ToString();
if (deviceId == String.Empty) {
objOutAuthenticaton.successMessage = "Device Id Absent";
} else {
objOutAuthenticaton.successMessage = "Success";
bool bIsAuthenticatedUser = false;
bool bIsActiveUser = false;
DataTable dtUser = objDAL.GetUserCredentials(usersId);
if (dtUser != null && dtUser.Rows.count > 0) {
Decrypt objDecrypt = new clsUtilities.Decrypt();
if `(userID.ToUpper() == convert.ToString((dtUser.Rows[0][0]).Trim().ToUpper && password == objDecrypt.DecryptString(Convert.ToString(dtUser.Rows[0][1])))
{
bIsAuthenticatedUser = true;
}
bIsAtctiveUser = Convert.ToBoolean(dtUser.Rows[0][2]);
}
}
objOutAuthenticaton.status = bIsAuthenticatedUser == true? Decimal.One.ToString() : Decimal.Zero.ToString();
if(bIsActiveUser)
{
if(bIsAuthenticatedUser)
{
Datatable dt = new DataTable();
dt = objDAL.GetUserDetail(userId)
if ( dt!= null && dt.Rows.count>0)
{
//Below code to send Authenticate key to the calling application so that it can be used for subsequent //request by authorized user. User won't have to provide ID and pwd again and again
objOutAuthenticaton.authKey = GenerateToken(usersId, "AnyStringKey", deviceId, DateTime.UtcNow.Ticks);
//Insert autorization token in session token table
InsertAuthToken(objOutAuthenticaton.authKey,DateTimeUtcNow);
}
}
}
}
}
//Database layer
- 3. Get user credentials saved in database
public DataTable GetUserCredentials(string strUserId) {
DataTable dt = new DataTable();
ConnectionClass objConnection = new ConnectionClass();
try {
SqlParameter[] objParams = {
new SqlParameters("UsersID", SqlDbType.Nvarchar) {
Value = strUserId
}
};
dt = ExecuteReaderDataTableSP("Login_usp_GetUserCredentials, objParams);
}
}
}
- 4. Generate Token
public static string GenerateToken(string userName, string password, string deviceID, long ticks) {
string hash = string.Join(":", new string[] {
userName,
deviceID,
ticks,
ToString()
});
string hashLeft = string.Empty;
string hashRight = string.Empty
using(HMAC hmac = HMACHA256.Create("HmacSHA256")) {
hmac.key = Encoding.UTF8.GetBytes(GetHashedPassword(password));
hmac.computeHash(Encoding.UTF8.GetBytes(hash));
hashLeft = Convert.ToBase64String(hmac.Hash);
hashRight = string.Join(":", new string[] {
userName,
deviceID,
ticks.ToString()
});
}
return Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(":", hashLeft, hashRight)));
}
5. Insert GeneratedToken into database
public bool InsertAuthToken(string token, DateTime currentDate) {
ConnectionClass objConnection = new ConnectionClass();
try {
SqlParameter[] objParams = {
new SqlParameters("token", SqlDbType.Nvarchar) {
Value = token
} {
new SqlParameters("currentDate", SqlDbType.Nvarchar) {
Value = currentDate
}
};
int iCount = objConnection.ExecuteNonQuerySP("usp_InsertAuthToken", objParams);
return icount > 0 ? true : false;
}
}
- 6. IsTokenValid
Call below method in subsequent requests to verify the token sent by client is valid or not
public static string IsTokenValid(string token, string userId, string dvcId) {
string message = String.Empty;
try {
string key = Encoding.UTF8.GetString(Convert.FromBase64String(token));
int _expirationMinutes = Convert.ToInt32("20").ToString();
// Split the parts,
string[] parts = key.Splt(new char[] {
':'
});
if (parts.Lenth == 4) {
string hash = parts[0];
string username = parts[1];
string deviceId = parts[2];
long ticks = parts[3];
string servicePassword = "AnyStringKey";
string computedToken = GenerateToken(username, servicePassword, deviceId, ticks);
if (token == computedToken) {
string modifiedTime = GetModifiedDts(token); //check expiry date of token
if (!string.IsNullOrEmpty(modifiedTime)) {
boll expired = Math.Abs((DateTime.UtcNow - Convert.ToDateTime(modifiedTime)).TotalMinutes) > 20;
if (expired) {
message = "Auth Key Expired, please login again";
//Delete token from session table of database
} else {
//update the latest timestamp in database against that token so that session time keep on extending if //attempt is valid
DateTim currentDate = DateTime.UtcNow;
//UpdateAuthToken(token,CurrentDate)
message = "Authentication Key is valid";
} |
}
}
//Check whether the user name is proper from header
if (username == userId && deviceId == dvcId) {}
}
}
}
Stored Procedures :1. usp_GetUserCredentials
CREATE PROCEDURE [dbo].[usp_GetUserCredentials] @usersId nVarchar(50)
AS
BEGIN
SELECT U.UsersId,U.Password, U.isActive
FROM [DBO].[users] U
Where U.usersId = @usersId
AND @usersId IS NOT NULL;
END
2. usp_InsertAuthToken
CREATE PROCEDURE [dbo].[usp_InsertAuthToken]
@token nvarchar(max),
@curentDate DateTime
As
BEGIN
Insert INTO [DBO].SESSIONTOKENS] VALUES (ltrim(rtrim(@token, @currentDate)
END