我有一个宁静的WCF服务,该服务托管在IIS中,使用WebHttpBinding和json通过SSL进行服务。
该服务现在需要身份验证/授权。似乎有很多旧的信息可能或可能不相关,以促进实现身份验证的不同方法,但是它们似乎都不适用于端点绑定的这种特定混合。
我玩过很多不同类型的绑定,使用基于SOAP的身份验证实现起来似乎比较简单,而使用json则不那么容易。大多数信息都指出IIS篡改了身份验证这一事实,但是我已经克服了这一障碍。
我想像这样使用基本身份验证(示例Fiddler请求):
GET https://secure.dev.myco.local/api/users/v1/0b7478c5-d25a-4039-9cf4-614b2ef4e04d HTTP/1.1
User-Agent: Fiddler
Host: secure.dev.myco.local
Authorization: Basic dGVzdHVzZXI6UEAkJHcwcmQh
我具有以下服务行为配置:
<behavior name="SslBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="CN=*.dev.myco.local" x509FindType="FindBySubjectDistinguishedName" storeLocation="LocalMachine" />
</serviceCredentials>
<serviceAuthenticationManager authenticationSchemes="Basic"
serviceAuthenticationManagerType="Test.Api.TestAuthenticationManager, Test.Api" />
</behavior>
绑定定义:
<webHttpBinding>
<binding name="ProductBinding">
<security mode="Transport" />
</binding>
<binding name="UserBinding">
<security mode="Transport" />
</binding>
</webHttpBinding>
和服务定义:
<service name="Test.Api.ApiService" behaviorConfiguration="SslServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://secure.dev.myco.local/api/"/>
</baseAddresses>
</host>
<endpoint address="products/v1" name="ProductService" contract="Test.Api.Product.V1.IProductService" binding="webHttpBinding" bindingConfiguration="ProductBinding" behaviorConfiguration="ProductEndpointWebHttpBehavior" />
<endpoint address="users/v1" name="UserService" contract="Test.Api.User.V1.IUserService" binding="webHttpBinding" bindingConfiguration="UserBinding" behaviorConfiguration="UserEndpointWebHttpBehavior" />
</service>
我的用户帐户将保存在数据库的表中,身份验证将凭据传递给身份验证提供程序,该身份验证提供程序出于所有目的和目的(如果用户进行身份验证,则返回IIdentity,IPrincipal或布尔值)。然后,将根据需要将其附加到上下文。因此,我需要我的应用程序处理身份验证,而不仅仅是将身份验证交给IIS。
我可以成功地从HTTP标头访问凭据,并通过从身份验证管理器派生并使用以下示例代码覆盖Authenticate方法来对用户进行身份验证-IPrincipal已生成,并按我期望的那样附加到上下文:
public class TestAuthenticationManager : ServiceAuthenticationManager
{
public override ReadOnlyCollection<IAuthorizationPolicy> Authenticate(ReadOnlyCollection<IAuthorizationPolicy> authPolicy, Uri listenUri, ref Message message)
{
var requestProperties =
(HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
var rawAuthHeader = requestProperties.Headers["Authorization"];
AuthenticationHeader authHeader = null;
if (AuthenticationHeader.TryDecode(rawAuthHeader, out authHeader)) ;
{
var identity = new GenericIdentity(authHeader.Username);
var principal = new GenericPrincipal(identity, new string[] {});
var httpContext = new HttpContextWrapper(HttpContext.Current)
{
User = principal,
};
if (httpContext.User != null)
return null;
}
SendUnauthorizedResponse();
return base.Authenticate(authPolicy, listenUri, ref message);
}
private void SendUnauthorizedResponse()
{
HttpContext.Current.Response.StatusCode = 401;
HttpContext.Current.Response.StatusDescription = "Unauthorized";
HttpContext.Current.Response.Headers.Add("WWW-Authenticate", "Basic realm=\"site\"");
HttpContext.Current.Response.End();
}
}
我遇到的麻烦是,退出validate方法后,我的服务将响应以下错误:
服务器在处理请求时遇到错误。异常消息是“呼叫者未通过服务验证。”。有关更多详细信息,请参见服务器日志。异常堆栈跟踪为:位于System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&rpc)处的System.ServiceModel.Dispatcher.AuthenticationBehavior.Authenticate(MessageRpc&rpc)位于System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
如果我从配置中删除了身份验证引用,该服务就可以正常工作-正如您所期望的那样,但是用户已通过身份验证,因此,如果我向任何服务方法中添加任何授权,它将无法处理该工作。
该方法似乎已退出,没有错误。谁能阐明我为什么在这种配置下会遇到此异常?我一直在Google搜寻,直到牛们回家,我发现的信息都与其他配置的有限数量的变体有关,但与WebHttpBinding和Json托管在带有SSL的IIS中无关。
线if (httpContext.User != null) return null;
是问题所在。如果Authenticate方法返回Null作为授权策略,则分派器将引发异常。
这里的条件始终为true,因此它将始终返回null。您需要返回授权策略,而不是null。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句