【问题标题】:WCF REST basic authentication on certain methods某些方法上的 WCF REST 基本身份验证
【发布时间】:2012-05-29 12:43:14
【问题描述】:

我在 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);

我浏览了很多博客和论坛,但仍然找不到符合要求的内容 我的要求。我需要对 一些 方法但不是全部实现基本身份验证。如果您查看上面的示例,我需要为 UpdateDetails 和 GetDetails 方法发送用户名和密码,但对于 Login 方法则不需要。然后根据数据库对用户名和密码进行身份验证。有可能做这样的事情吗?

附带说明:这些 REST 方法被许多不同的移动设备调用。

我查看了以下站点,它们都通过 REST 实现了基本身份验证它们涵盖了上述所有方法。

有没有可能做我想做的事?

【问题讨论】:

    标签: c# wcf security rest mobile


    【解决方案1】:

    我创建了一个 BasicAuthenticationInvoker 类,您可以将它归于您想要进行身份验证的方法,如下所示:

      [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;
            }
        }
    

    【讨论】:

    • 如果我想让 QuickQuote 的响应依赖于登录的用户怎么办?换句话说:如何在调用的 QuickQuote 方法中获取凭据?
    • 你真的应该研究一下 ServiceStack 而不是 WCF。
    • 我知道这是旧的,但@Dylan 应该在 Authenticate("Client name here") 中添加什么?
    猜你喜欢
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 2011-02-04
    • 2015-04-14
    • 1970-01-01
    相关资源
    最近更新 更多