2015-10-22 3 views
0

Итак, на этом этапе, пытаясь получить эту работу, я прибегаю к задаче задать вам этот вопрос.Не удается получить стандартную аутентификацию WCF для аутентификации пользователя

Да, я прошел через кучу вопросов переполнения стека, похожих на мои, но безрезультатно.

Все, что я хочу сделать, это добавить базовую аутентификацию через SSL. Из миллионов и половин тысяч 44 тысяч и 7 обучающих программ, которые я просматривал, это действительно кажется простой задачей.

Все, что я получаю, это всплывающее диалоговое окно, которое запрашивает у меня имя пользователя и пароль, но даже если я передаю ему правильные учетные данные, он просто появляется снова и снова.

Я также играл с настройками конфигурации в iis express. Если я отключу базовую аутентификацию, я получаю сообщение о том, что это не включено.

Я знаю, что я являюсь белокурая, но прежде чем я положил дыру в моем экране вот мой web.config

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> 

    <!--DIAGNOSTICS--> 
    <system.diagnostics> 
    <trace autoflush="true"/> 
    <sources> 
     <source name="System.ServiceModel" 
       switchValue="Information, ActivityTracing" 
       propagateActivity="true"> 
     <listeners> 
      <add name="ServiceModel" 
       type="System.Diagnostics.XmlWriterTraceListener" 
       initializeData="C:\ServiceModel.svclog" /> 
     </listeners> 
     </source> 
     <source name="System.ServiceModel.MessageLogging"> 
     <listeners> 
      <add name="MessageLogging" 
       type="System.Diagnostics.XmlWriterTraceListener" 
       initializeData="C:\MessageLogging.svclog" /> 
     </listeners> 
     </source> 
    </sources> 
    </system.diagnostics> 

    <system.serviceModel> 

    <diagnostics> 
     <messageLogging logEntireMessage="True" 
         logMalformedMessages="False" 
         logMessagesAtServiceLevel="True" 
         logMessagesAtTransportLevel="False" 
         maxMessagesToLog="10000" 
         maxSizeOfMessageToLog="10000" /> 
    </diagnostics> 

    <bindings> 

     <webHttpBinding> 
     <binding name="SSSLayer"> 
      <security mode="Transport"> 
      <transport clientCredentialType="Basic"></transport> 
      </security> 
     </binding> 
     </webHttpBinding> 
    </bindings> 

    <services> 
     <service behaviorConfiguration="serviceBehaviour" name="Booky.Machine_SVC"> 
     <endpoint address="" 
        behaviorConfiguration="RESTBehaviour" 
        binding="webHttpBinding" 
        bindingConfiguration="SSSLayer" 
        contract="Booky.IMachine_SVC" /> 
     </service> 
    </services> 


    <behaviors> 
     <endpointBehaviors> 
     <behavior name="RESTBehaviour"> 
      <webHttp/> 
     </behavior>     
     </endpointBehaviors> 

     <serviceBehaviors> 
     <behavior name="serviceBehaviour"> 
      <!-- 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"/> 

      <!--<serviceCredentials> 
      <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Booky.Authentication, Booky" /> 
      </serviceCredentials>--> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 


    <protocolMapping> 
     <add binding="basicHttpsBinding" scheme="https" /> 
    </protocolMapping>  
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> 
    </system.serviceModel> 
    <system.webServer> 
    <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="true"/> 
    </system.webServer> 

</configuration> 

Authentication Class

namespace Booky 
{ 
    public class Authentication : System.IdentityModel.Selectors.UserNamePasswordValidator 
    { 
     public override void Validate(string UserName, string Password) 
     { 
      if (UserName == null || Password == null) 
      { 
       throw new ArgumentNullException("Username or Password is Incorrect"); 
      } 

      if (!(UserName == "wickd" && Password == "OMIG2015")) 
      { 
       throw new Exception("Invalid Credentials"); 
      } 
     } 
    } 
} 

Machine_SVC

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults=true)] 
    public class Machine_SVC : IMachine_SVC 
    { 
     /// <summary> 
     /// Retrieves a serial number 
     /// </summary> 
     /// <param name="serial"></param> 
     /// <returns></returns> 
     Machine IMachine_SVC.GetMachine(string serial) 
     { 
      var res = Machine.GetMachine(serial); 

      if (CheckContent(res)) 
       return res; 
      else 
       return null; 
     } 

     /// <summary> 
     /// Creates a new machine object 
     /// </summary> 
     /// <param name="machine"></param> 
     void IMachine_SVC.CreateMachine(Machine machine) 
     { 
      if (!Machine.CreateMachine(machine)) 
      { 
       WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.PreconditionFailed; 
       WebOperationContext.Current.OutgoingResponse.StatusDescription = "A serial and status needs to be specified for the machine to be created"; 
      } 
     } 

     /// <summary> 
     /// This will update the machine information 
     /// </summary> 
     /// <param name="machine"></param> 
     /// <param name="serial"></param> 
     void IMachine_SVC.UpdateMachineInfo(Machine machine, string serial) 
     { 
      var result = Machine.UpdateMachineInfo(machine, serial); 

      CheckUpdateCreateResult(result); 
     } 

     private bool CheckContent(object result, HttpStatusCode code = HttpStatusCode.NotFound) 
     { 
      if (result != null) 
      { 
       return true; 
      } 
      else 
      { 
       WebOperationContext.Current.OutgoingResponse.StatusCode = code; 
       return false; 
      } 
     } 

     private void CheckUpdateCreateResult(ReturnCodes result) 
     { 
      if (result == ReturnCodes.DATASETINCOMPLETE) 
      { 
       WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.PreconditionFailed; 
       WebOperationContext.Current.OutgoingResponse.StatusDescription = "Not all the required attributes were provided. You need a serial, bitlocked, model and type attribute"; 
      } 

      if (result == ReturnCodes.INVALIDDATA) 
      { 
       WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.PreconditionFailed; 
       WebOperationContext.Current.OutgoingResponse.StatusDescription = "The serial provided in the url is not the same as in the json object"; 
      } 

      if (result == ReturnCodes.NOTEXIST) 
      { 
       WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; 
       WebOperationContext.Current.OutgoingResponse.StatusDescription = "The serial you have provided does not exist yet! You need to create it first!"; 
      } 
     } 

     /// <summary> 
     /// Retrieves a list of owners of the machine with the owners organized from last login first 
     /// </summary> 
     /// <param name="serial"></param> 
     /// <returns></returns> 
     List<MachineOwner> IMachine_SVC.GetMachineOwners(string serial) 
     { 
      var owners = MachineOwners.GetOwners(serial); 

      if (CheckContent(owners)) 
       return owners; 
      else 
       return null; 
     } 

     /// <summary> 
     /// Adds a new Machine owner. Only adds the serial, nothing else 
     /// </summary> 
     /// <param name="owner"></param> 
     /// <param name="serial"></param> 
     void IMachine_SVC.AddMachineOwner(MachineOwner owner, string serial) 
     { 
      var result = MachineOwners.AddOwner(owner, serial); 

      CheckUpdateCreateResult(result); 
     } 

     /// <summary> 
     /// Retrieves the statuses for a particular machine 
     /// </summary> 
     /// <param name="serial"></param> 
     /// <returns></returns> 
     List<MachineStatus> IMachine_SVC.GetMachineStatuses(string serial) 
     { 
      var statuses = MachineStatus.GetStatusList(serial); 

      if (CheckContent(statuses)) 
       return statuses; 
      else 
       return null; 
     } 

     /// <summary> 
     /// This will update a machine status. 
     ///  - Checks that the operation is valid compared to last machine login 
     ///  - Checks that status is indeed valid 
     /// </summary> 
     /// <param name="serial"></param> 
     /// <param name="status"></param> 
     void IMachine_SVC.UpdateMachineStatus(string serial, MachineStatus status) 
     { 
      var result = MachineStatus.UpdateStatus(serial, status); 

      CheckUpdateCreateResult(result); 
     } 

     /// <summary> 
     /// Retrieves a list of all machines ever registered on the network 
     /// </summary> 
     /// <returns></returns> 
     List<Machine> IMachine_SVC.GetAllMachines() 
     { 
      var machines = Machines.GetAllMachines(); 

      if (CheckContent(machines)) 
       return machines; 
      else 
       return null; 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="search"></param> 
     void IMachine_SVC.CreateMachineSearch(MachineSearch search) 
     { 
      throw new NotImplementedException(); 
     } 
    } 

IMachine_SVC

[ServiceContract] 
    public interface IMachine_SVC 
    { 
     [OperationContract] 
     [WebInvoke(Method="GET", 
      RequestFormat=WebMessageFormat.Json, 
      BodyStyle=WebMessageBodyStyle.Bare, 
      ResponseFormat=WebMessageFormat.Json, 
      UriTemplate="/machine/{serial}")] 
     Machine GetMachine(string serial); 

     [OperationContract] 
     [WebInvoke(Method = "PUT", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machine/{serial}")] 
     void UpdateMachineInfo(Machine machine, string serial); 

     [OperationContract] 
     [WebInvoke(Method = "POST", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machine")] 
     void CreateMachine(Machine machine); 

     [OperationContract] 
     [WebInvoke(Method = "GET", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machine/{serial}/owners")] 
     List<MachineOwner> GetMachineOwners(string serial); 

     [OperationContract] 
     [WebInvoke(Method = "POST", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machine/{serial}/owner")] 
     void AddMachineOwner(MachineOwner owner, string serial); 

     [OperationContract] 
     [WebInvoke(Method = "GET", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machine/{serial}/statuses")] 
     List<MachineStatus> GetMachineStatuses(string serial); 

     [OperationContract] 
     [WebInvoke(Method = "PUT", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machine/{serial}/status")] 
     void UpdateMachineStatus(string serial, MachineStatus status); 

     [OperationContract] 
     [WebInvoke(Method = "GET", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machines")] 
     List<Machine> GetAllMachines(); 

     [OperationContract] 
     [WebInvoke(Method = "POST", 
      RequestFormat = WebMessageFormat.Json, 
      BodyStyle = WebMessageBodyStyle.Bare, 
      ResponseFormat = WebMessageFormat.Json, 
      UriTemplate = "/machines")] 
     void CreateMachineSearch(MachineSearch search); 
    } 
+0

Вы отлаживали свое решение. Получаете ли вы метод Validate внутри своего пользовательского ** UserNamePasswordValidator ** или нет? – Mimas

+0

Я отлаживал и устанавливал соответствующие точки останова, но, похоже, не входил в пользовательский метод проверки. Затем я подумал, что это имеет какое-то отношение к базовой настройке аутентификации IIS и отключил его, но это не решает проблему ... – wickd

+0

У меня действительно нет прямого ответа на вопрос, но если бы я был вами, я бы начали шаг за шагом. Сначала я бы изменил привязку к wsHttpBinding и попытался воспроизвести это в коде (взяв этот пример https://msdn.microsoft.com/en-us/library/ms733775.aspx) и используя C# -записной клиент. Если это сработает, это будет означать, что ваш валидатор, по крайней мере, признан и применен.И я бы не пошел дальше, этот простой образец MSDN работает – Mimas

ответ

1

Если вы размещаете эту услугу в IIS, то вы будете сталкиваться с проблемой, так как пароль валидатор заказ не был построен для размещения IIS. Он будет отлично работать с автономным хостингом. См. Подробности here, где Фил четко заявил, что Обратите внимание, что это поддерживается только при самообслуживании.

Вместо использования пользовательского валидатора вы можете достичь этого, расширив класс «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("Please provide a username and password", HttpStatusCode.Unauthorized); 
     } 
    } 
} 

Добавить RestAuthorizationManager в режим обслуживания.

<serviceBehaviors> 
    <behavior name="ServiceBehavior"> 
    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> 
    <serviceDebug includeExceptionDetailInFaults="true"/> 
    <serviceAuthorization 
     serviceAuthorizationManagerType 
     =" WcfWebHttpIISHostingSample.RestAuthorizationManager, WcfWebHttpIISHostingSample"/> 
    </behavior> 
</serviceBehaviors> 

Это должно вас заставить.

Я написал complete guide для создания и обеспечения безопасности службы WCF REST с помощью базовой аутентификации с помощью SSL. Вы можете пройти через это, даже поведение безопасности также является частью расширения library действий WCF REST и webhttp. См. Сведения о персонализированном обслуживании.

+0

работает ли ваш гид, когда wcf размещается внутри iis? – Dizzle

+0

Да, это руководство распространяется на корпус iis. – vendettamit

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