Introduction
WCF Restful Service methods can be accessed by URL only. I had to apply Authentication so that only Authentic users can access that method. I searched a lot to apply WCF Restful Service authentication using username password without SSL Certificate but could not find anything. Then I went for form Authentication.
Using the Code
First, we need to create one WCF service. I have created a service LoginSevice.svc for authenticating users. Also, I have created a user table and an edmx file importing that table.
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode =
InstanceContextMode.PerCall,IncludeExceptionDetailInFaults=true)]
public class LoginService : ILoginService
{
TestEntities1 db = new TestEntities1(); public bool Login(string userName, string password)
{
bool returnValue = false;
UserTable user;
using (var ctx = new TestEntities())
{
user = ctx.UserTables.Where(one => one.UserName == userName).FirstOrDefault();
if (user != null)
{
returnValue = (user.Password == password);
}
}
if (returnValue)
{
var loginTicket= new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddDays(1),
true,
user.Id.ToString()
);
string encryptedTicket = FormsAuthentication.Encrypt(loginTicket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(cookie);
}
return returnValue;
}
}
Now, we define OperationContract
in ILoginService
as shown below:
[ServiceContract]
public interface ILoginService
{
[OperationContract]
bool Login(string userName, string password);
}
Now, I added one more class for defining Restful Service Method named RestfullServiceMethod
.
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class RestfullServiceMethod
{
[WebInvoke(UriTemplate = "/GetTest",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public string GetTest()
{
return "test";
}
}
Now in service web.config file, we need to change authentication mode to Form add apply Authorization like Allow user Deny User like below:
<configuration>
<connectionStrings>
<!-- For Edmx Connection String-->
<add name="TestEntities" connectionString="
metadata=res://*/WCFModel.csdl|res://*/WCFModel.ssdl|res://*/WCFModel.msl;
provider=System.Data.SqlClient;provider connection string="
Data Source=.;Initial Catalog=Test;User ID=sa;
Password=sa;MultipleActiveResultSets=True""
providerName="System.Data.EntityClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Data.Entity,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
-->
<authentication mode="Forms">
</authentication>
-->
<authorization>
<deny users="?" />
</authorization>
</system.web>
<location path="LoginService.svc">
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,
System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="true"
automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>
Now, I need to consume that WCF Service normally Restful service method can call by URL using webRequest
class but I need to apply authentication. That way, I validate the user first and pass that token in header request. For testing these, I have created one webapplication and that service Reference to that webapplication. Now, I am explaining the code of how to call that service in our webapplication after adding reference:
using System.ServiceModel;
using WebApplication1.LoginService;
using System.ServiceModel.Channels;
using System.Net;
using System.IO;
using System.Xml;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var sharedCookie = string.Empty;
bool isValid;
string data = string.Empty;
var authClient = new LoginServiceClient();
using (new OperationContextScope(authClient.InnerChannel))
{
isValid = authClient.Login("test", "abc123");
if (isValid)
{
var response = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
sharedCookie = response.Headers["Set-Cookie"];
}
}
if (isValid)
{
var request =
(HttpWebRequest)WebRequest.Create("http://localhost:9025/RestfullServiceMethod/GetTest");
request.Timeout = 30000;
request.Method = "POST";
request.ContentType = "text/xml";
request.Headers["Cookie"] = sharedCookie;
HttpWebResponse res = null;
res = (HttpWebResponse)request.GetResponse();
Stream responseStream = res.GetResponseStream();
var streamReader = new StreamReader(responseStream);
string str = string.Empty;
str = streamReader.ReadToEnd();
lblResult.Text = str;
}
We can also get user detail by that authentication token in RestfullService
class:
[WebGet(UriTemplate = "/GetTest",
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public string GetTest()
{
string testcookie = HttpContext.Current.Request.Cookies
[FormsAuthentication.FormsCookieName].Value;
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(testcookie);
string UserName=authTicket.Name;
return "test";
}