2014-10-24 3 views
1

Я сделал очень простое приложение WCF и нашел одну проблему, которую я не могу решить. относительно службы WCF, которая фактически работает, если анонимная аутентификация включена, но когда я отключу эту функцию в IIS, она дает мне ошибку: HTTP-запрос неавторизован с помощью схемы аутентификации клиента «Аноним». Заголовок аутентификации, полученный от сервера был ''WCF не работает с отключенной функцией анонимной аутентификации в IIS

IIS configuration

это конфигурация web.config:

<?xml version="1.0"?> 
<configuration> 

<appSettings> 
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> 
</appSettings> 
<system.web> 
<compilation debug="true" targetFramework="4.5" /> 
<httpRuntime targetFramework="4.5"/> 
</system.web> 
<system.serviceModel> 
<services> 
    <service name="WCFTestApplication.WCFTestApplication"> 
    <endpoint address="" 
       binding="wsHttpBinding" 
       bindingConfiguration="WCFTestAppBinding" 
       contract="WCFTestApplication.IWCFTestApplication" 
    /> 
    <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" /> 
    </service> 
    </services> 
    <bindings> 
    <wsHttpBinding> 
    <binding messageEncoding="Text" name="WCFTestAppBinding"> 
     <security mode="TransportWithMessageCredential"> 
     <message clientCredentialType="Windows"/> 
     <transport clientCredentialType="Windows" proxyCredentialType="Windows"/> 
     </security> 
    </binding> 
    </wsHttpBinding> 
    </bindings> 
    <behaviors> 
    <serviceBehaviors> 
    <behavior> 
     <!-- To avoid disclosing metadata information, set the values below to false before deployment --> 
     <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/> 
     <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> 
     <serviceDebug includeExceptionDetailInFaults="false"/> 
    </behavior> 
    </serviceBehaviors> 
    </behaviors> 
    <!--protocolMapping> 
    <add binding="basicHttpsBinding" scheme="https" /> 
    </protocolMapping-->  
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> 
</system.serviceModel> 
<system.webServer> 
<validation validateIntegratedModeConfiguration="false"/> 
<modules runAllManagedModulesForAllRequests="true"/> 
    <!-- 
    To browse web app root directory during debugging, set the value below to true. 
    Set to false before deployment to avoid disclosing web app folder information. 
    --> 
    <directoryBrowse enabled="false"/> 
</system.webServer> 

это источник клиентского приложения:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Security.Cryptography.X509Certificates; 
using System.Net.Security; 
using System.Net; 

namespace WCFClientApplication 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private string _name = ""; 
    private string _passwd = ""; 
    private string _domain = ""; 

    public string UserName 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public string Password 
    { 
     get { return _passwd; } 
     set { _passwd = value; } 
    } 

    public string Domain 
    { 
     get { return _domain; } 
     set { _domain = value; } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     //if (!String.IsNullOrEmpty(usrTxt.Text) || !String.IsNullOrEmpty(passTxt.Text) || !String.IsNullOrEmpty(domainTxt.Text)) 
     //{ 
      UserName = usrTxt.Text; 
      Password = passTxt.Text; 
      Domain = domainTxt.Text; 

      WCFClientProxy.WCFTestApplicationClient client = new WCFClientProxy.WCFTestApplicationClient(); 
      client.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(UserName, Password, Domain); 
      //System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => { return true; }; 
      textBox1.Text = client.GetData(); 
     //} 
     //else 
     //{ 
     // MessageBox.Show("Fields like username, password and domain must not be blank...!","Warning...!",MessageBoxButtons.OK, MessageBoxIcon.Warning); 
     //} 
    } 

    private void domainTxt_MouseHover(object sender, EventArgs e) 
    { 
     tipLbl.Visible = true; 
    } 

    private void domainTxt_MouseLeave(object sender, EventArgs e) 
    { 
     tipLbl.Visible = false; 
    } 
} 
} 

Интерфейс wcf:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.ServiceModel.Web; 
using System.Text; 

namespace WCFTestApplication 
{ 
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together. 
[ServiceContract] 
public interface IWCFTestApplication 
{ 

    [OperationContract] 
    string GetData(); 

    // TODO: Add your service operations here 
} 
} 

Класс:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.ServiceModel.Web; 
using System.Text; 

namespace WCFTestApplication 
{ 
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together. 
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging. 
public class WCFTestApplication : IWCFTestApplication 
{ 
    public string GetData() 
    { 
     return "WCF is working, and message is authenticated and encrypted"; 
    } 
} 
} 

Я где-то читал, что анонимная проверка подлинности есть что-то с MEX конечной точки и связи, но как же я могу сохранить окна логин и отключить анонимный вход пользователя так, WCF не может быть использована Whithout надлежащие полномочия?

+0

Почему вы включили аутентификацию формы? Также в соответствии с конфигурацией вы использовали аутентификацию Windows и ее нет в IIS. – dotnetstep

+0

Привет, учтите немного? Я установил Windows auth в файле конфигурации, но вам не нужно указывать имя пользователя, пароль и домен для учетных данных клиента? 'client.ClientCredentials.Windows.ClientCredential = новый System.Net.NetworkCredential (имя пользователя, пароль, домен);' – dovla091

+0

Вы правы. В IIS Authentication не отображается «Аутентификация Windows». вы должны установить этот протокол, перейдя в раздел «Включить или отключить функцию». – dotnetstep

ответ

1

Я наконец-то нашел решение:

Web.config

<?xml version="1.0"?> 
<configuration> 

<appSettings> 
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> 
</appSettings> 
<system.web> 
<authentication mode="Windows" /> 
<compilation debug="true" targetFramework="4.5" /> 
<httpRuntime targetFramework="4.5"/> 
</system.web> 
<system.serviceModel> 
<services> 
    <service name="WCFTestApplication.WCFTestApplication"> 
    <endpoint address="" 
       binding="wsHttpBinding" 
       bindingConfiguration="WCFTestAppBinding" 
       contract="WCFTestApplication.IWCFTestApplication" 
    /> 
    <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" /> 
    </service> 
</services> 
<bindings> 
    <wsHttpBinding> 
    <binding messageEncoding="Text" name="WCFTestAppBinding"> 
     <security mode="Transport"> 
     <transport clientCredentialType="Ntlm"/> 
     </security> 
    </binding> 
    </wsHttpBinding> 
</bindings> 
<behaviors> 
    <serviceBehaviors> 
    <behavior> 
     <serviceCredentials> 
     <windowsAuthentication allowAnonymousLogons="false" includeWindowsGroups="true"/> 
     </serviceCredentials> 
     <!-- To avoid disclosing metadata information, set the values below to false before deployment --> 
     <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/> 
     <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> 
     <serviceDebug includeExceptionDetailInFaults="true"/> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 
<!--protocolMapping> 
    <add binding="basicHttpsBinding" scheme="https" /> 
</protocolMapping-->  
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> 
</system.serviceModel> 
<system.webServer> 
<validation validateIntegratedModeConfiguration="false"/> 
<modules runAllManagedModulesForAllRequests="true"/> 
<!-- 
    To browse web app root directory during debugging, set the value below to true. 
    Set to false before deployment to avoid disclosing web app folder information. 
    --> 
<directoryBrowse enabled="false"/> 
</system.webServer> 
</configuration> 

app.config

<?xml version="1.0"?> 
<configuration> 
<configSections> 
</configSections> 
<startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> 
</startup> 
<system.serviceModel> 
    <bindings> 
     <wsHttpBinding> 
      <binding name="WSHttpBinding_IWCFTestApplication"> 
       <security mode="Transport"> 
        <transport clientCredentialType="Ntlm" /> 
       </security> 
      </binding> 
     </wsHttpBinding> 
    </bindings> 
    <client> 
     <endpoint address="https://vladimir.intra.jv.hr/WCFTestApplication.svc" 
      binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWCFTestApplication" 
      contract="WCFTestApplication.IWCFTestApplication" name="WSHttpBinding_IWCFTestApplication"> 
      <identity> 
       <servicePrincipalName value="host/vladimir.intra.jv.hr" /> 
      </identity> 
     </endpoint> 
    </client> 
    </system.serviceModel> 
    </configuration> 

Form1.cs

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Security.Cryptography.X509Certificates; 
using System.Net.Security; 
using System.Net; 

namespace WCFClientApplication 
{ 
public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private string _name = ""; 
    private string _passwd = ""; 
    private string _domain = ""; 

    public string UserName 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    public string Password 
    { 
     get { return _passwd; } 
     set { _passwd = value; } 
    } 

    public string Domain 
    { 
     get { return _domain; } 
     set { _domain = value; } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     //if (!String.IsNullOrEmpty(usrTxt.Text) || !String.IsNullOrEmpty(passTxt.Text) || !String.IsNullOrEmpty(domainTxt.Text)) 
     //{ 

      UserName = usrTxt.Text; 
      Password = passTxt.Text; 
      Domain = domainTxt.Text; 

      WCFTestApplication.WCFTestApplicationClient client = new WCFTestApplication.WCFTestApplicationClient(); 

      client.ClientCredentials.Windows.ClientCredential.Domain = Domain; 
      client.ClientCredentials.Windows.ClientCredential.UserName = UserName; 
      client.ClientCredentials.Windows.ClientCredential.Password = Password; 
      //this part needs to be modified, so certificate can be accepted from other machines as well. 
      System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => { return true; }; 
      textBox1.Text = client.GetData(); 
      client.Close(); 
     //} 
     //else 
     //{ 
     // MessageBox.Show("Fields like username, password and domain must not be blank...!","Warning...!",MessageBoxButtons.OK, MessageBoxIcon.Warning); 
     //} 
    } 

    private void domainTxt_MouseHover(object sender, EventArgs e) 
    { 
     tipLbl.Visible = true; 
    } 

    private void domainTxt_MouseLeave(object sender, EventArgs e) 
    { 
     tipLbl.Visible = false; 
    } 
    } 
} 

Интерфейс

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.ServiceModel.Web; 
using System.Text; 

namespace WCFTestApplication 
{ 
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together. 
[ServiceContract] 
public interface IWCFTestApplication 
{ 

    [OperationContract] 
    string GetData(); 

    // TODO: Add your service operations here 
} 
} 

Класс

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.ServiceModel; 
using System.ServiceModel.Web; 
using System.Text; 

namespace WCFTestApplication 
{ 
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together. 
// NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging. 
public class WCFTestApplication : IWCFTestApplication 
{ 
    public string GetData() 
    { 
     return "WCF is working, and message is authenticated and encrypted"; 
    } 
} 
} 

Я скопировал весь код, так что другие могут учиться немного, и найти все, что необходимо для создания собственной конфигурации. Таким образом, это настройка, включающая SSL, wsHttpBinding и аутентификацию Windows/NTLM для веб-службы.

Дело в том, что я шел совершенно в другом направлении, тратя время на настройку IIS и пытаясь разорить свои отбивные, почему аутентификация не работала в первую очередь, когда я отключил анонимную аутентификацию. Дело в том, что мне не пришлось беспокоить себя с помощью IIS, поскольку вся часть безопасности выполняется через WCF. Так что я сделал, включил анонимную аутентификацию. Существует хорошая причина, по которой вам это нужно: без этого вы не можете обновлять ссылку на веб-сайт клиента. (по крайней мере, я не мог ...). О да. Это не означает, что кто-либо может использовать службу WCF без входа в систему сначала ... Во-вторых, что меня смущает, я был в том же домене, поэтому каждый раз, когда вы включали анонимную аутентификацию, я получал бы результаты от службы WCF без какой-либо информации о регистрации который предоставляется в клиентском прокси-объекте класса.Дело в том, что когда я использовал другой компьютер, который не находится в домене, я не мог получить результаты, пока не предоставляю имя пользователя, пароль и домен.

P.S. И последнее, но не менее важное: часть кода в клиентском приложении: System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => { return true; }; - это точка безопасности, это реальный риск для безопасности. Я добавил этот код для тестирования, из-за того, что на другой машине, которая не находится в домене, не удалось установить доверительные отношения для защищенного канала SSL/TLS с полномочием «server.domain».

И, наконец, спасибо всем за помощь. Cheers.

Смежные вопросы