Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to authenticate in WCF services in BasicHttpBinding?

I am developing WCF services with basicHttpBinding, these services should be accessible using .net 1.1 & .net 2.0, for this purpose I am using basicHttpBinding.
In old ASMX web services I assed one Soap Header (AuthHeader) to authenticate the user every request.

How Can I authenticate in WCF using basicHttpBinding? Any sample Or tutorial will helpfull.


nRk

like image 658
nRk Avatar asked Dec 29 '22 10:12

nRk


1 Answers

You can use AuthHeader as you did before switching to WCF. Maybe it will be more convinient for you, cause the princples will remain the same. The bad thing i see in this solution is a plain text password transfer. Anyway, it's just another option and you can encrypt/decrypt the password somehow.

In this case you should implement your own your IDispatchMessageInspector & IClientMessageInspector, like

[AttributeUsage(AttributeTargets.Class)]
public class CredentialsExtractorBehaviorAttribute : Attribute, IContractBehavior, IDispatchMessageInspector
{
    #region IContractBehavior implementation.

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint,
                                      DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.MessageInspectors.Add(this);
    }

    ... empty interface methods impl skipped ...

    #endregion

    #region IDispatchMessageInspector implementation.

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        int i = request.Headers.FindHeader("username", "sec");
        if (-1 != i)
        {
            string username = request.Headers.GetHeader<string>("username", "sec");
            ... do smth ...
        }
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        return;
    }

    #endregion
}

In a sample i placed to header only username, but you can implement your a class containing username and password and use it instead of string. On the client:

internal class CredentialsInserter : IContractBehavior, IClientMessageInspector
{
    private string m_username;

    public CredentialsInserter(string username)
    {
        m_username = username;
    }

    #region IContractBehavior implementation.

    ... empty interface methods impl skipped ...

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint,
                                    ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(this);
    }

    #endregion

    #region IClientMessageInspector implementation.

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        MessageHeader<string> mh = new MessageHeader<string>(m_username);
        request.Headers.Add(mh.GetUntypedHeader("username", "sec"));
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        return;
    }

    #endregion
}

Then you should place attribute CredentialsExtractorBehaviorAttribute on your service implementation class.

[CredentialsExtractorBehavior]
public class DummyService : IDummyService
{
   ... impl ...
}

And on the client side you should do the following:

        using (DummyServiceClient c = new DummyServiceClient("TcpEndpoint"))
        {
            c.ChannelFactory.Endpoint.Contract.Behaviors.Add(
                new CredentialsInserter("_username_"));
            c.DummyMethod();
        }
like image 101
fspirit Avatar answered Jan 07 '23 00:01

fspirit