使用WCF REST服务进行基本身份验证的内置方法?

时间:2013-12-03 14:19:48

标签: c# ajax wcf basic-authentication wcf-rest

我在WCF服务中使用基本身份验证。 并且还使用ASP Membership provider进行身份验证。

Web.Config中: 对于REST服务:

<webHttpBinding>
    <binding name="webHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="200065536" maxBufferPoolSize="200065536" maxReceivedMessageSize="200065536"   transferMode="Buffered" useDefaultWebProxy="true">
      <readerQuotas maxDepth="202048000" maxStringContentLength="202048000" maxArrayLength="202048000"
                    maxBytesPerRead="202048000" maxNameTableCharCount="202048000"/>
      <security mode="Transport">  
      </security>
    </binding>
  </webHttpBinding>

身份验证类型和模式:

<serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="CustomMemberShipProvider" />
</serviceCredentials>

调用任何方法之前的BasicAuthentication的自定义类。 代码如下所示:

namespace BasicAuth.Service
{
    public class BasicAuthenticationInvoker : Attribute, IOperationBehavior, IOperationInvoker
    {
        #region Private Fields

        private IOperationInvoker _invoker;

        #endregion Private Fields

        #region IOperationBehavior Members

        public void ApplyDispatchBehavior(OperationDescription operationDescription,
                                          DispatchOperation dispatchOperation)
        {
            _invoker = dispatchOperation.Invoker;
            dispatchOperation.Invoker = this;
        }

        public void ApplyClientBehavior(OperationDescription operationDescription,
                                        ClientOperation clientOperation)
        {
        }

        public void AddBindingParameters(OperationDescription operationDescription,
                                         BindingParameterCollection bindingParameters)
        {
        }

        public void Validate(OperationDescription operationDescription)
        {
        }

        #endregion IOperationBehavior Members

        #region IOperationInvoker Members

        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
            System.Diagnostics.Debugger.Break();
            if (Authenticate())
                return _invoker.Invoke(instance, inputs, out outputs);
            else
            {
                outputs = null;
                return null;
            }
        }

        public object[] AllocateInputs()
        {
            return _invoker.AllocateInputs();
        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs,
                                        AsyncCallback callback, object state)
        {
            throw new NotSupportedException();
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            throw new NotSupportedException();
        }

        public bool IsSynchronous
        {
            get
            {
                return true;
            }
        }

        #endregion IOperationInvoker Members

        private bool Authenticate()
        {
            string[] credentials = GetCredentials(WebOperationContext.Current.IncomingRequest.Headers);

            if (credentials != null && credentials.Length == 2)
            {
                var username = credentials[0];
                var password = credentials[1];
                if (Membership.ValidateUser(username, password))  //if valid user
                {
                    //get the roles of the user
                    string[] roles = Roles.GetRolesForUser(username);
                    Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(username), roles);
                    return true;
                }
            }
            WebOperationContext.Current.OutgoingResponse.Headers["WWW-Authenticate"] = string.Format("Basic realm=\"{0}\"", string.Empty);
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
            return false;
        }

        private string[] GetCredentials(WebHeaderCollection headers)
        {
            string credentials = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];
            if (credentials != null)
                credentials = credentials.Trim();

            if (!string.IsNullOrEmpty(credentials))
            {
                try
                {
                    string[] credentialParts = credentials.Split(new[] { ' ' });
                    if (credentialParts.Length == 2 && credentialParts[0].Equals("basic", StringComparison.OrdinalIgnoreCase))
                    {
                        credentials = Encoding.ASCII.GetString(Convert.FromBase64String(credentialParts[1]));
                        credentialParts = credentials.Split(new[] { ':' });
                        if (credentialParts.Length == 2)
                            return credentialParts;
                    }
                }
                catch (Exception ex)
                {

                }
            }

            return null;
        }
    }
}

我的Iservice如下所示:

My Custom类用作Iservice合约中的属性

public interface IService1
    {
        [OperationContract]
        [BasicAuthenticationInvoker] //my custom class for authentication
        [WebGet(UriTemplate = "GetString?userID={userID}",
            ResponseFormat = WebMessageFormat.Json)]
        string GetString(string userID);
   }

使用 AJAX调用调用WCF REST服务时,我将Authentication头添加到请求中,并使用上述自定义类对用户进行身份验证。

AJAX致电: 下面是用于调用服务的Ajax调用,并使用beforeSend在访问服务之前对用户进行身份验证。

<script>
             $(function () {
                 alert("onload");
                 $.ajax
                     ({
                         type: "GET",
                         data:jsondata,
                         url: https://localhost:446/BasicAuthService.svc/rest/GetString',
                         cache: false,
                         async: true,
                         crossDomain:true,
                         dataType: "json",
                         contentType: "application/json; charset=utf-8",
                         beforeSend: function (xhr) {                             
                             xhr.setRequestHeader('Authorization', 'Basic plc2gxMjMk');
                         },
                         error: function(jqXHR, exception)
                         {
                             alert(jqXHR.status+" "+exception);
                         }
                     });
             });
  </script>

我的问题是:

我希望你能全面了解我的代码是如何工作的。

所以我需要的是,而不是使用自定义类进行BasicAuthentication,如何验证每个服务请求? WCF 中是否有 In-build功能用于验证传入请求?

提前致谢。

1 个答案:

答案 0 :(得分:0)

您的安全模式应指定基本身份验证:

<security mode="Transport">
    <transport clientCredentialType="Basic" />
</security>