我正在尝试公开WCT REST服务,只有拥有有效用户名和密码的用户才能访问它。用户名和密码存储在SQL数据库中。
这是服务合同:
public interface IDataService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
byte[] GetData(double startTime, double endTime);
}
以下是WCF配置:
<bindings>
<webHttpBinding>
<binding name="SecureBinding">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="DataServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType=
"CustomValidator, WCFHost" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="DataServiceBehavior" name="DataService">
<endpoint address="" binding="webHttpBinding"
bindingConfiguration="SecureBinding" contract="IDataService" />
</service>
</services>
我通过Silverlight应用程序中的WebClient类访问该服务。但是,我无法弄清楚如何将用户凭据传递给服务。我为client.Credentials尝试了各种值,但它们似乎都没有在我的自定义验证器中触发代码。我收到以下错误:基础连接已关闭:发送时发生意外错误。
以下是我尝试的一些示例代码:
WebClient client = new WebClient();
client.Credentials = new NetworkCredential("name", "password", "domain");
client.OpenReadCompleted += new OpenReadCompletedEventHandler(GetData);
client.OpenReadAsync(new Uri(uriString));
如果我将安全模式设置为None,则整个过程都有效。我还尝试了其他clientCredentialType值,但没有一个工作。我还自行托管了WCF服务,以消除与IIS尝试在服务获得机会之前对用户进行身份验证相关的问题。
对基础问题可能存在的任何评论都将非常感激。感谢。
更新:感谢穆罕默德的出色建议。这是我的跟踪配置:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.IdentityModel" switchValue="Information,
ActivityTracing" propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
但是我没有看到来自我的Silverlight客户端的任何消息。至于https vs http,我使用https如下:
string baseAddress = "https://localhost:6600/";
_webServiceHost = new WebServiceHost(typeof(DataServices),
new Uri(baseAddress));
_webServiceHost.Open();
但是,我没有配置任何SSL证书。这是问题吗?
答案 0 :(得分:2)
由于您使用的是“基本”身份验证,因此您需要在请求标头中发送用户名和密码。手动将凭据添加到标题的示例如下所示:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"https://localhost:6600/MyWCFService/GetData");
//Add a header to the request that contains the credentials
//DO NOT HARDCODE IN PRODUCTION!! Pull credentials real-time from database or other store.
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("userName" + ":" + "password"));
req.Headers.Add("Authorization", "Basic " + svcCredentials);
//Parse the response and do something with it...
using (WebResponse svcResponse = (HttpWebResponse)req.GetResponse())
{
using (StreamReader sr = new StreamReader(svcResponse.GetResponseStream()))
{
//Sample parses json response; your code here may be different
JavaScriptSerializer js = new JavaScriptSerializer();
string jsonTxt = sr.ReadToEnd();
}
}
答案 1 :(得分:0)
首先,您可能希望向服务添加WCF跟踪以获取更多详细信息。其次,我认为问题可能是您以明文形式发送用户凭据,而WCF不允许通过不安全的传输通道以明文形式传输用户凭据。因此,请尝试使用https或指定加密算法以通过http保护用户凭据。
答案 2 :(得分:0)
上面建议的 atconway 似乎是正确的方法,但您的服务必须从标头读取基本64字符串数据并转换回字符串然后进行身份验证。但它需要在每次通话时进行身份验证。
另一种方法是使用安全密钥。和令牌
对于extream安全性
拥有私钥/公钥对,客户端将使用公钥加密整个帖子数据,您将使用私钥解密。