How do I restrict access to some methods in WCF?

后端 未结 2 658
遥遥无期
遥遥无期 2020-12-13 15:37

I am a bit lost getting started with a simple WCF service. I have two methods and I want to expose one to the world and the second one I want to limit to certain users. Ev

相关标签:
2条回答
  • 2020-12-13 16:25

    Use the following steps to restrict access to specific Windows users:

    • Open the Computer Management Windows applet.
    • Create a Windows group that contains the specific Windows users to which you wish to give access. For example, a group can be called “CalculatorClients”.
    • Configure your service to require ClientCredentialType = “Windows”. This will require clients to connect using Windows authentication.
    • Configure your service methods with the PrincipalPermission attribute to require connecting users be members of the CalculatorClients group.
    // Only members of the CalculatorClients group can call this method.
    [PrincipalPermission(SecurityAction.Demand, Role = "CalculatorClients")]
    public double Add(double a, double b)
    { 
    return a + b; 
    }
    
    0 讨论(0)
  • 2020-12-13 16:30

    A lot of the answers I found were almost what I needed but not quite right. I wound up setting up ASP.net membership and implementing a custom attribute to pull an authorization header and process login as the request came in. All of the magic happens in BeforeCall and ParseAuthorizationHeader below:

    public class UsernamePasswordAuthentication : Attribute, IOperationBehavior, IParameterInspector
    {
        public void ApplyDispatchBehavior(OperationDescription operationDescription,
            DispatchOperation dispatchOperation)
        {
            dispatchOperation.ParameterInspectors.Add(this);
        }
    
        public void AfterCall(string operationName, object[] outputs,
                              object returnValue, object correlationState)
        {
        }
    
        public object BeforeCall(string operationName, object[] inputs)
        {
            var usernamePasswordString = parseAuthorizationHeader(WebOperationContext.Current.IncomingRequest);
            if (usernamePasswordString != null)
            {
                string[] usernamePasswordArray = usernamePasswordString.Split(new char[] { ':' });
                string username = usernamePasswordArray[0];
                string password = usernamePasswordArray[1];
                if ((username != null) && (password != null) && (Membership.ValidateUser(username, password)))
                {
                    Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(username), new string[0]);
                    return null;
                }
            }
    
            // if we made it here the user is not authorized
            WebOperationContext.Current.OutgoingResponse.StatusCode =
                HttpStatusCode.Unauthorized;
            throw new WebFaultException<string>("Unauthorized", HttpStatusCode.Unauthorized);            
        }
    
        private string parseAuthorizationHeader(IncomingWebRequestContext request)
        {
            string rtnString = null;
            string authHeader = request.Headers["Authorization"];
            if (authHeader != null)
            {
                var authStr = authHeader.Trim();
                if (authStr.IndexOf("Basic", 0) == 0)
                {
                    string encodedCredentials = authStr.Substring(6);
                    byte[] decodedBytes = Convert.FromBase64String(encodedCredentials);
                    rtnString = new ASCIIEncoding().GetString(decodedBytes);
                }
            }
            return rtnString;
        }
    
        public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }
    
        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
        }
    
        public void Validate(OperationDescription operationDescription)
        {
        }
    
    }
    

    From there I just need to add my new attribute to the service contract entries. Any request to that method will require a valid authorization header or a Not Authorized response will be sent back with doing any further processing.

    [ServiceContract]
    interface ILocationService
    {
        [OperationContract]
        string GetLocation(string id);
    
        [OperationContract]
        [UsernamePasswordAuthentication]  // this attribute will force authentication
        string GetHiddenLocation(string id);
    }
    
    0 讨论(0)
提交回复
热议问题