某些方法的WCF REST基本身份validation

我在WCF 4.0中实现了很多RESTful(GET和POST)方法。 所有这些都通过SSL工作。

一些方法的示例:

[OperationContract] [WebInvoke(UriTemplate = "Login?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] LoginResponse Login(LoginRequest request); [OperationContract] [WebInvoke(UriTemplate = "UpdateDetails?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] UpdateUserDetailResponse UpdateDetails(UpdateUserDetailRequest request); [OperationContract] [WebInvoke(UriTemplate = "GetDetails?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] UserDetailResponse GetDetails(UserDetailRequest request); 

我浏览了很多博客和论坛,但仍然找不到符合我要求的东西。 我需要对某些方法实现基本身份validation,但不是全部。 如果你看一下上面的例子,我需要为UpdateDetails和GetDetails方法发送用户名和密码,而不是Login方法。 然后,对数据库validation用户名和密码。 有可能做这样的事吗?

作为旁注:这些REST方法由许多不同的移动设备调用。

我查看了以下站点,它们都通过REST实现基本身份validation, 它们涵盖了上面提到的所有方法。

  • http://msdn.microsoft.com/en-us/library/aa702565.aspx
  • 将基本HTTP身份validation添加到WCF REST服务
  • http://custombasicauth.codeplex.com/ (底部的链接不再起作用)

有可能做我想做的事吗?

我创建了一个BasicAuthenticationInvoker类,您可以根据要进行身份validation的方法进行操作,如下所示:

  [OperationContract] [BasicAuthenticationInvoker] // this is the auth attribute! [WebInvoke(UriTemplate = "QuickQuote?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] QuickQuoteResponse QuickQuote(QuickQuoteRequest request); 

实际的类看起来如下:

  public class BasicAuthenticationInvoker : Attribute, IOperationBehavior, IOperationInvoker { #region Private Fields private IOperationInvoker _invoker; #endregion #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 #region IOperationInvoker Members public object Invoke(object instance, object[] inputs, out object[] outputs) { if (Authenticate("Client Name here")) 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 private bool Authenticate(string realm) { string[] credentials = GetCredentials(WebOperationContext.Current.IncomingRequest.Headers); if (credentials != null && credentials.Length == 2) { // do auth here var username = credentials[0]; var password = credentials[1]; // validate the username and password against whatever auth logic you have return true; // if successful } WebOperationContext.Current.OutgoingResponse.Headers["WWW-Authenticate"] = string.Format("Basic realm=\"{0}\"", realm); 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 { } } return null; } }