WCF - REST和SOAP的多个端点

时间:2015-10-19 19:23:21

标签: c# web-services wcf rest soap

我正在尝试使用REST和SOAP端点编写WCF服务。我最初使用" TransportCredentialOnly"用于SOAP端点。当我开始添加REST端点时...我正在使用第三方OAUTH 1.0类来为REST服务提供安全性。

使用" TransportCredentialOnly"身份验证,我必须启用" Windows身份验证"在IIS网站应用程序上。

我遇到的问题是REST调用回来了"身份验证失败"因为IIS希望在命中REST端点之前使用Windows凭据进行初始身份验证。

我启用了#34;匿名身份验证"在IIS应用程序上,但在继续之前仍会提示您输入Windows凭据。

无论如何都要保持" Windows身份验证" SOAP调用的方案,并在REST端点上进行匿名身份验证(将继续使用OAuth 1.0)?我并不是真的想将它分成两个项目/服务,因为一些函数/方法/类在SOAP和REST调用之间是通用的。

到目前为止,这是我的网络配置尝试:

<system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
    <authentication mode="Windows"/>
    <authorization>
      <allow roles="DOMAIN\Security_Group"/>
      <deny users="*"/>
    </authorization>
    <customErrors mode="Off"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpEndpointBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows"/>
          </security>
        </binding>
      </basicHttpBinding>
      <webHttpBinding>
            <binding name="webHttpBindingWithJsonP" />
      </webHttpBinding>
    </bindings>
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="Anonymous">
            <security mode="None"/>
        </standardEndpoint>
      </webHttpEndpoint>
    </standardEndpoints>
    <services>
       <service name="service name">      
        <endpoint address="SOAP"
                  binding="basicHttpBinding"
                  bindingConfiguration="BasicHttpEndpointBinding"
                  contract="contract name">
          <identity>
             <dns value="localhost" />
          </identity>
        </endpoint>        
        <endpoint address="REST"
                  kind="webHttpEndpoint"
                  binding ="webHttpBinding"
                  bindingConfiguration="webHttpBindingWithJsonP"
                  endpointConfiguration="Anonymous"
                  behaviorConfiguration="restBehavior"
                  contract ="contract name">
        </endpoint>   
        <host>
          <baseAddresses>
            <add baseAddress="service url"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="restBehavior">
          <webHttp helpEnabled="true" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <useRequestHeadersForMetadataAddress/>
        </behavior>    
      </serviceBehaviors>
    </behaviors>
    <!--<protocolMapping>
      <add binding="basicHttpsBinding" scheme="http" />
    </protocolMapping>-->
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="false" />
  </system.serviceModel>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <!--<add name="Access-Control-Allow-Origin" value="*"/>
        <add name="Access-Control-Allow-Methods" value="POST,GET"/>
        <add name="Access-Control-Allow-Headers" value="Content-Type, Accept"/>-->
      </customHeaders>
    </httpProtocol>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

10-20-2015更新:我在web.config文件中应用了一个新的配置来使用serviceAuthorization

<service name="service name"  behaviorConfiguration="Oauth">
<endpoint address="service address"               
          binding ="webHttpBinding"
          behaviorConfiguration="restBehavior"
          contract ="service contract">
</endpoint>
<host>
  <baseAddresses>
    <add baseAddress="base address"/>
  </baseAddresses>
</host>
</service>

<behavior name="Oauth">
  <serviceMetadata httpGetEnabled="true" />
  <serviceDebug includeExceptionDetailInFaults="false" />
  <serviceAuthorization serviceAuthorizationManagerType="Assembly.OAuthAuthorizationManager,Assembly" />
</behavior>

这是OAuthorizationManager类:

 public class OAuthAuthorizationManager : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        bool Authenticated = false;

        string normalizedUrl;
        string normalizedRequestParameters;

        base.CheckAccessCore(operationContext);

        // to get the httpmethod

        HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)(operationContext.RequestContext.RequestMessage).Properties[HttpRequestMessageProperty.Name];

        string httpmethod = requestProperty.Method;

        // HttpContext.Current is null, so forget about it 
        // HttpContext context = HttpContext.Current; 

        NameValueCollection pa = HttpUtility.ParseQueryString(operationContext.IncomingMessageProperties.Via.Query);

        if (pa != null && pa["oauth_consumer_key"] != null)
        {
            // to get uri without oauth parameters
            string uri = operationContext.IncomingMessageProperties
            .Via.OriginalString.Replace
               (operationContext.IncomingMessageProperties
            .Via.Query, "");

            string consumersecret = "secret";

            OAuthBase oauth = new OAuthBase();

            string hash = oauth.GenerateSignature(
                new Uri(uri),
                pa["oauth_consumer_key"],
                consumersecret,
                null, // totken
                null, //token secret
                httpmethod,
                pa["oauth_timestamp"],
                pa["oauth_nonce"],
                out normalizedUrl,
                out normalizedRequestParameters
                );
            Authenticated = pa["oauth_signature"] == hash;
        }
        return Authenticated;
    }
}

1 个答案:

答案 0 :(得分:0)

在IIS中托管基于REST的WCF服务有一个可行的解决方案可以使用自己的自定义基本身份验证。您可以轻松地发回一个响应标头来挑战基本身份验证凭据,并且只需将IIS连接到ServiceAuthorizationManager。在这种情况下,IIS将只负责托管和它。

创建一个继承自public class RestAuthorizationManager : ServiceAuthorizationManager { protected override bool CheckAccessCore(OperationContext operationContext) { //Extract the Authorization header, and parse out the credentials converting the Base64 string: var authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"]; if ((authHeader != null) && (authHeader != string.Empty)) { var svcCredentials = System.Text.ASCIIEncoding.ASCII .GetString(Convert.FromBase64String(authHeader.Substring(6))) .Split(':'); var user = new { Name = svcCredentials[0], Password = svcCredentials[1] }; if ((user.Name == "user1" && user.Password == "test")) { //User is authrized and originating call will proceed return true; } else { //not authorized return false; } } else { //No authorization header was provided, so challenge the client to provide before proceeding: WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"MyWCFService\""); //Throw an exception with the associated HTTP status code equivalent to HTTP status 401 throw new WebFaultException(HttpStatusCode.Unauthorized); } } } 的自定义授权管理器类,并将其配置为您的服务。

<serviceBehaviors>
  <behavior name="SecureRESTSvcTestBehavior">
    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceAuthorization serviceAuthorizationManagerType="WcfRestAuthentication.Services.Api.RestAuthorizationManager, WcfRestAuthentication"/>
  </behavior>
</serviceBehaviors>

将以上自定义授权管理器添加到配置:

Error: spawn C: \Users\ myusername\ Documents\ GitHub\ angular - testing - tutorial\ node_m
odules\ gulp - protractor\ node_modules\.bin\ protractor.cmd ENOENT
at exports._errnoException(util.js: 746: 11)
at Process.ChildProcess._handle.onexit(child_process.js: 1053: 32)
at child_process.js: 1144: 20
at process._tickCallback(node.js: 355: 11)

将以上行为仅应用于REST端点。现在IIS再也无法控制任何授权。确保使用SSL证书确保以明文形式发送信用证。