WCF authorize request to endpoint

I am developing a WCF REST service where requests are authenticated using basic authentication over SSL. However, before I send the authentication challenge I want to ensure that the request is valid using a pre-shared API key. I do not want the key value passed in the URL so is a custom HTTP header the best solution? Something like X-APIKey: keyvalue.

I am authenticating the user's credentials in a HttpModule:

public void OnAuthenticateRequest(object source, EventArgs eventArgs)
    {
        HttpApplication app = (HttpApplication)source;

        if (!app.Request.IsSecureConnection)
        {
            app.Response.StatusCode = 403;
            app.Response.StatusDescription = "SSL Required";
            app.Response.End();
            return;
        }

        string authHeader = app.Request.Headers[AUTH_HEADER];
        if (authHeader == null)
        {
            app.Response.StatusCode = 401;
            app.Response.End();
            return;
        }

        ClientCredentials credentials = ClientCredentials.FromHeader(authHeader);
        if (credentials.Authenticate())
        {
            app.Context.User = new GenericPrincipal(new GenericIdentity(credentials.Id), null);
        }
        else
        {
            DenyAccess(app);
        }
    }

That's a good alternative (passing it in a header). You can then use a custom message inspector to validate that the shared key is present in all requests for a specific endpoint, as shown in the code below.

public class StackOverflow_13463251
{
    const string SharedKeyHeaderName = "X-API-Key";
    const string SharedKey = "ThisIsMySharedKey";
    [ServiceContract]
    public interface ITest
    {
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        string Echo(string text);
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        int Add(int x, int y);
    }
    public class Service : ITest
    {
        public string Echo(string text)
        {
            return text;
        }
        public int Add(int x, int y)
        {
            return x + y;
        }
    }
    public class ValidateSharedKeyInspector : IEndpointBehavior, IDispatchMessageInspector
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            HttpRequestMessageProperty httpReq = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
            string apiKey = httpReq.Headers[SharedKeyHeaderName];
            if (!SharedKey.Equals(apiKey))
            {
                throw new WebFaultException<string>("Missing api key", HttpStatusCode.Unauthorized);
            }

            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
        }
    }
    static void SendRequest(string uri, bool includeKey)
    {
        string responseBody = null;
        Console.WriteLine("Request to {0}, {1}", uri, includeKey ? "including shared key" : "without shared key");

        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
        req.Method = "GET";
        if (includeKey)
        {
            req.Headers[SharedKeyHeaderName] = SharedKey;
        }

        HttpWebResponse resp;
        try
        {
            resp = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException e)
        {
            resp = (HttpWebResponse)e.Response;
        }

        Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
        foreach (string headerName in resp.Headers.AllKeys)
        {
            Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
        }

        Console.WriteLine();
        Stream respStream = resp.GetResponseStream();
        responseBody = new StreamReader(respStream).ReadToEnd();
        Console.WriteLine(responseBody);

        Console.WriteLine();
        Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
        Console.WriteLine();
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "");
        endpoint.Behaviors.Add(new WebHttpBehavior());
        endpoint.Behaviors.Add(new ValidateSharedKeyInspector());
        host.Open();
        Console.WriteLine("Host opened");

        SendRequest(baseAddress + "/Echo?text=Hello+world", false);
        SendRequest(baseAddress + "/Echo?text=Hello+world", true);
        SendRequest(baseAddress + "/Add?x=6&y=8", false);
        SendRequest(baseAddress + "/Add?x=6&y=8", true);

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
链接地址: http://www.djcxy.com/p/26900.html

上一篇: 不再支持?

下一篇: WCF向端点授权请求