65.9K
CodeProject is changing. Read more.
Home

WCF Restful Service Form Authentication

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (5 votes)

Nov 6, 2014

CPOL

1 min read

viewsIcon

32984

downloadIcon

4

WCF Restful Service Authentication without SSL Certificate

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();//Edmx entity Object
        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=&quot;
    Data Source=.;Initial Catalog=Test;User ID=sa;
    Password=sa;MultipleActiveResultSets=True&quot;" 
    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>
    <!--For apply authentication Mode form-->
    <authentication mode="Forms">
    </authentication>
    <!--For Access only Authorized user -->
    <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";
        }