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

我在我的 WCF 服务中使用基本身份验证。并且还使用 ASP Membership 提供程序进行身份验证。

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 如下所示:

我的自定义类用作 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 标头添加到 Request 并使用上述自定义类对用户进行身份验证。

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 功能用于验证传入请求?

提前致谢。

stack overflow Built-in way to do Basic Authentication with WCF REST service?
原文答案

答案:

作者头像

Your security mode should specify basic authentication:

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