首先,我是WCF的新手。我使用WCF创建了一个REST Web服务。它只有一个检索产品列表的操作(json格式)。这是使用jquery从web调用的。它工作得很好。
现在,我需要的是向Web服务添加一个自定义身份验证。是否可以将其添加到webHttpBinding?我添加了验证:
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (null == userName || null == password)
{
throw new ArgumentNullException();
}
if (userName != "testuser")
{
throw new SecurityTokenException("Unknown Username or Password");
}
}
}
我试图更改web.config以使其工作,但我做不到。
这是我在没有自定义身份验证的情况下工作的web.config:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding crossDomainScriptAccessEnabled="true">
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="WCFEndPointBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyRestService.ServiceAuthenticator, MyRestService" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="MyRestService.ProductRESTService" behaviorConfiguration="ServiceBehavior">
<endpoint address=""
behaviorConfiguration="WCFEndPointBehavior"
binding="webHttpBinding"
contract="MyRestService.IProductRESTService">
<identity>
<dns
value="localhost"/>
</identity>
</endpoint>
</service>
</services>
以下是调用ws的jquery:
$("#myButton").click(function () {
var artistURL = "http://localhost:56866/ProductRESTService.svc/GetProductList/";
var returnData = "";
$.ajax({
cache: false,
type: "GET",
async: false,
processData: true,
data: "",
url: artistURL,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Basic " + btoa("testuser:123456789"));
},
error: function (request, status, error) { alert("Error"); },
success: function (data, status, jqXHR) {
$("div#myOutput").html(" ");
returnData = "<table style='font-size:12pt;font-family:sans-serif'><tr><th>Product</th><th></th></tr>";
for (prop in data) {
if (!data.hasOwnProperty(prop)) { continue; }
if (data[prop] != null) {
for (var i = 0; i < data[prop].length; i++) {
returnData += "<tr><td>" + data[prop][i]["ProductId"]
+ " " + data[prop][i]["Name"] + "</td><td align='right'>"
+ data[prop][i]["CategoryName"] + "</td></tr>";
}
}
}
returnData = returnData + "</table>";
$("div#myOutput").html(returnData);
}
});
return (false);
});
当我执行此操作时,它工作正常,但从未到达自定义验证器。我的web.config中缺少什么吗?如何将自定义身份验证应用于此类Web服务?
我正在使用:.NET Framework 4.5带有VS2012 的IIS Express
提前感谢!
编辑
身份验证由IIS执行,这就是为什么没有触发自定义验证的原因。有一些解决办法:
- 自托管服务
- ISS Hosted使用ServiceAuthorizationManager执行自定义身份验证(它应该用于授权,没有身份验证,但这是我找到的唯一方法)。这里有更多信息:使用webHttpBinding对IIS托管的REST服务进行基本身份验证
如果有人有其他解决方法。。。你可以自由评论!我希望这能有所帮助。
我知道我参加聚会迟到了,但我只需要用我自己的一个服务解决这个问题,IIS盗用了身份验证,而且不清楚发生了什么或如何解决,所以下面是一个循序渐进的步骤:
首先创建一个执行身份验证的类:
您的类必须派生自System.IdentityModel.Selectors(System.Identity Model)命名空间中的UserNamePasswordValidator:
using System.IdentityModel.Selectors;
namespace MyProject
{
public class CustomUserNameValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (username != "Bob" || password != "Letmein")
through new SecurityTokenException("If you're name's not Bob, you're not coming in!")
}
}
}
下一步您需要为您的开发端点提供SSL证书:
有许多教程可用于生成您自己的自签名证书。我使用了这个教程,但有很多,你可能会找到其他更简单的方法。由于浏览器对自签名证书的限制,我使用直接自签名证书成功率有限。为了避免这种情况,我使用相同的过程创建了根证书颁发机构,然后使用我的RCA创建了一个签名证书。这似乎满足了浏览器的限制,并消除了任何警告。[严格地说,这很可能是超出需求的,但警告让我很困扰。]
创建SSL证书后,请使用certificates.msc将其注册到证书(本地计算机)\个人\证书中。
将IIS端点与端口443(或您希望的任何端口)绑定,以获得您刚刚创建的证书。
接下来,您需要定义一个服务行为:
您的服务行为必须包含对凭据验证器和SSL证书的引用。
<behavior name="MyCustomCredentialBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyProject.MyCustomCredentialValidator, MyAssembly" />
<serviceCertificate findValue="CN=*.dev.myco.com"
x509FindType="FindBySubjectDistinguishedName"
storeLocation="LocalMachine" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
</behavior>
您可以使用可分辨名称或指纹来引用您的证书。在我的例子中,我使用了创建证书时选择的可分辨名称。如果你使用指纹,复制/粘贴指纹时要小心,因为序列开头有一个字节标记字符,会破坏你的引用,所以你的应用程序找不到它。手动复制序列比沮丧更容易,或者通过其他明文编辑器(如记事本)复制,可以去掉未打印的字符。
最后,您需要您的服务配置来参考您的服务行为:
<service name="MySecureService"
behaviorConfiguration="MyCustomCredentialBehavior">
<host>
<baseAddresses>
<add baseAddress="https://myservice.com/mysecureservice/" />
</baseAddresses>
</host>
<endpoint name="MySecureServiceEndpoint"
binding="webHttpBinding"
contract="IMySecureService" />
</service>
如果我没有记错的话,这应该是你所需要的一切。