C# WCF-REST和SOAP的多个端点

C# WCF-REST和SOAP的多个端点,c#,web-services,wcf,rest,soap,C#,Web Services,Wcf,Rest,Soap,我试图用REST和SOAP端点编写一个WCF服务。我最初对SOAP端点使用“TransportCredentialOnly”。当我开始添加REST端点时……我正在使用第三方OAUTH 1.0类为REST服务提供安全性 使用“TransportCredentialOnly”身份验证,我必须在IIS网站应用程序上启用“Windows身份验证” 我遇到的问题是,REST调用返回时带有“身份验证失败”,因为IIS希望在命中REST端点之前使用Windows凭据进行初始身份验证 我在IIS应用程序上启用了

我试图用REST和SOAP端点编写一个WCF服务。我最初对SOAP端点使用“TransportCredentialOnly”。当我开始添加REST端点时……我正在使用第三方OAUTH 1.0类为REST服务提供安全性

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

我遇到的问题是,REST调用返回时带有“身份验证失败”,因为IIS希望在命中REST端点之前使用Windows凭据进行初始身份验证

我在IIS应用程序上启用了“匿名身份验证”,但在继续之前仍会提示输入Windows凭据

是否仍然需要为SOAP调用保留“Windows身份验证”方案,并在REST端点上进行匿名身份验证(将继续使用OAuth 1.0)?我真的不想把它分成两个项目/服务,因为一些函数/方法/类在SOAP和REST调用之间是通用的

以下是迄今为止我的web配置:

<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>

有一个可行的解决方案,即在IIS中托管基于REST的WCF服务,并且可以使用其自己的自定义基本身份验证。您可以轻松地发回一个响应头来质询基本身份验证凭据,只需将IIS连接到
“匿名身份验证”。
在这种情况下,IIS只负责托管,仅此而已

创建从
ServiceAuthorizationManager
继承的自定义授权管理器类,并将其配置到您的服务

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>


仅将上述行为应用于其余端点。现在IIS将不再控制这里的任何授权。请确保使用SSL证书来保护凭据不以纯文本形式发送。

Hmmm,有没有办法使用此方法并将其应用于OAuth?在我现有的其余端点上…它们使用使用者密钥和密码执行OAuth1.0身份验证。这是可行的…只是想知道是否有任何方法可以在IIS授权上使用匿名身份验证来访问REST端点。通过一些调整,可以在AuthorizationManager中访问OAuth所需的请求负载。如果服务托管在IIS中,则WCF可以访问HttpContext.Current。因此,您可以使用它来获取传入请求并尽您所能。。。您所说的IIS授权是什么意思?请看一下ServiceAuthroizationManager中OAuth使用的示例。IIS授权…我指的是正在承载的应用程序下IIS中的“身份验证”设置。因此,对于“身份验证”设置,我启用了“Windows身份验证”和“匿名身份验证”。当我尝试向WCF服务发送GET时,似乎收到了“未授权”响应,因为IIS应用程序由于启用了“Windows身份验证”设置而阻止了请求。这很好。如果您对任何其他身份验证类型进行了
匿名身份验证
,则除非通过配置明确指定,否则不会强制windows身份验证。
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>