无法获取 WCF 基本身份验证以对用户进行身份验证
Cannot Get WCF Basic authentication to authenticate user
所以在这个阶段,在尝试让这个工作之后,我现在求助于问你们很多这个问题。
是的,我经历了一堆与我类似的堆栈溢出问题,但无济于事。
我只想通过 SSL 添加基本身份验证。从我翻阅的 100 万 44000 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>
身份验证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();
}
}
我Machine_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);
}
如果您在 IIS 中托管此服务,那么您将面临问题,因为自定义密码验证程序不是为 IIS 托管构建的。它与独立托管一起工作得很好。查看详细信息 here,其中 Phil 明确指出 请注意,这仅在自托管服务下受支持。
您可以通过扩展 "ServiceAuthorizationManager" class 而不是使用自定义验证器来实现它。
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 for creating and securing WCF REST service with Basic Authentication with SSL. You may want to go through it even the security behavior is also a part of an extension library WCF REST 和 webhttp 行为。请参阅 CustomAuthenticationBehavior 详细信息。
所以在这个阶段,在尝试让这个工作之后,我现在求助于问你们很多这个问题。
是的,我经历了一堆与我类似的堆栈溢出问题,但无济于事。
我只想通过 SSL 添加基本身份验证。从我翻阅的 100 万 44000 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>
身份验证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();
}
}
我Machine_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);
}
如果您在 IIS 中托管此服务,那么您将面临问题,因为自定义密码验证程序不是为 IIS 托管构建的。它与独立托管一起工作得很好。查看详细信息 here,其中 Phil 明确指出 请注意,这仅在自托管服务下受支持。
您可以通过扩展 "ServiceAuthorizationManager" class 而不是使用自定义验证器来实现它。
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 for creating and securing WCF REST service with Basic Authentication with SSL. You may want to go through it even the security behavior is also a part of an extension library WCF REST 和 webhttp 行为。请参阅 CustomAuthenticationBehavior 详细信息。