向 WCF + Autofac 无扩展服务添加身份验证
Add authentication to WCF + Autofac extensionless service
我正在寻找一种方法来为我的 WCF 服务设置简单的用户名 + 密码身份验证。它们是使用 Autofac extensionless services 设置的。这意味着我的 Global.asax 看起来像这样:
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyWcfService>().InstancePerLifetimeScope();
var container = builder.Build();
AutofacHostFactory.Container = container;
AutofacHostFactory.HostConfigurationAction =
host =>
{
host.Description.Behaviors.Add(container.Resolve<MyCustomBehavior>());
};
RouteTable.Routes.Add(new ServiceRoute("my/custom/route", new AutofacServiceHostFactory(), typeof(MyWcfService)));
}
}
我的 Web.config 看起来像这样:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="10485760">
<readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
</system.webServer>
如您所见,我没有任何 *.svc 文件,我的 Web.config 中也没有 <services>
部分来配置我的服务。现在我需要为此服务添加基本的用户名+密码身份验证。我已按照 this Microsoft tutorial 中的步骤进行操作,但从未调用 CustomUserNameValidator
。
我根据教程所做的更改是:
- 添加
CustomUserNamePasswordValidator
- 将 serviceCredentials 部分添加到 Web.config
中的行为
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="My.ServiceHost.CustomUserNamePasswordValidator, My.ServiceHost"/>
</serviceCredentials>
- 将我在 Web.config 中的绑定更新为:
<wsHttpBinding>
<binding name="authQuotaBinding" maxReceivedMessageSize="10485760">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
<readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
</binding>
</wsHttpBinding>
我在本地使用 IIS Express 托管该服务。我缺少哪一块拼图才能让它发挥作用?
有几条信息缺失,可能是拼图缺失的部分。
您通过 Autofac 在所有主机上定义了自定义行为,但不清楚此自定义行为在做什么and/or如果这与您的问题有关?
您已经定义了自定义验证器,当用户名用于身份验证并需要验证时(在 serviceCredentials 部分),但是这只会在您使用 wsHttpBinding 时触发调用您的服务。但是,我在您的服务和此绑定之间没有看到任何 link?您确定该服务正在使用该绑定吗?还是它仍在使用您的 basicHttpBinding?通常这会在每个服务的配置中配置,但由于您使用的是 AutoFac,我假设 Autofac 正在 linking 配置绑定到您的服务。可能是哪里出了问题?
我的猜测是你需要在Autofac中指定这个,或者你可能还需要更新这部分配置:
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
进入
<protocolMapping>
<add binding="wsHttpBinding" scheme="http" />
</protocolMapping>
或者如果你想更具体
<protocolMapping>
<add binding="wsHttpBinding" bindingConfiguration="authQuotaBinding" scheme="http" />
</protocolMapping>
但这取决于名称为 basicHttpsBinding 的绑定的定义。 (似乎也没有包含在提供的信息中?)
有关协议映射的更多信息,请参阅:https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/protocolmapping
除此之外,您的要求也可能是改用此配置:
<wsHttpBinding>
...
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
...
</wsHttpBinding>
这与您是想使用 SOAP 消息 encryption/signing 确保消息的完整性还是对 HTTPS 提供的完整性感到满意有关。
根据您问题中 linked 的文章,您甚至可以使用 basicHttpBinding 而不是 wsHttpBinding 并使用安全模式设置为 Transport 并将传输部分的 clientCredentialType 属性设置为 Basic 例如,
<basicHttpBinding>
...
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
...
</basicHttpBinding>
有关不同安全模式的详细信息,请参阅:https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/security-of-wshttpbinding
最后,我也不建议保留 serviceDebug 设置,该设置允许您将异常详细信息包含在生产环境中。 (当然这又取决于您的要求)
我正在寻找一种方法来为我的 WCF 服务设置简单的用户名 + 密码身份验证。它们是使用 Autofac extensionless services 设置的。这意味着我的 Global.asax 看起来像这样:
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyWcfService>().InstancePerLifetimeScope();
var container = builder.Build();
AutofacHostFactory.Container = container;
AutofacHostFactory.HostConfigurationAction =
host =>
{
host.Description.Behaviors.Add(container.Resolve<MyCustomBehavior>());
};
RouteTable.Routes.Add(new ServiceRoute("my/custom/route", new AutofacServiceHostFactory(), typeof(MyWcfService)));
}
}
我的 Web.config 看起来像这样:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="10485760">
<readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
</system.webServer>
如您所见,我没有任何 *.svc 文件,我的 Web.config 中也没有 <services>
部分来配置我的服务。现在我需要为此服务添加基本的用户名+密码身份验证。我已按照 this Microsoft tutorial 中的步骤进行操作,但从未调用 CustomUserNameValidator
。
我根据教程所做的更改是:
- 添加
CustomUserNamePasswordValidator
- 将 serviceCredentials 部分添加到 Web.config 中的行为
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="My.ServiceHost.CustomUserNamePasswordValidator, My.ServiceHost"/>
</serviceCredentials>
- 将我在 Web.config 中的绑定更新为:
<wsHttpBinding>
<binding name="authQuotaBinding" maxReceivedMessageSize="10485760">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
<readerQuotas maxDepth="32" maxStringContentLength="10485760" maxArrayLength="10485760" maxBytesPerRead="10485760" />
</binding>
</wsHttpBinding>
我在本地使用 IIS Express 托管该服务。我缺少哪一块拼图才能让它发挥作用?
有几条信息缺失,可能是拼图缺失的部分。
您通过 Autofac 在所有主机上定义了自定义行为,但不清楚此自定义行为在做什么and/or如果这与您的问题有关?
您已经定义了自定义验证器,当用户名用于身份验证并需要验证时(在 serviceCredentials 部分),但是这只会在您使用 wsHttpBinding 时触发调用您的服务。但是,我在您的服务和此绑定之间没有看到任何 link?您确定该服务正在使用该绑定吗?还是它仍在使用您的 basicHttpBinding?通常这会在每个服务的配置中配置,但由于您使用的是 AutoFac,我假设 Autofac 正在 linking 配置绑定到您的服务。可能是哪里出了问题?
我的猜测是你需要在Autofac中指定这个,或者你可能还需要更新这部分配置:
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
进入
<protocolMapping>
<add binding="wsHttpBinding" scheme="http" />
</protocolMapping>
或者如果你想更具体
<protocolMapping>
<add binding="wsHttpBinding" bindingConfiguration="authQuotaBinding" scheme="http" />
</protocolMapping>
但这取决于名称为 basicHttpsBinding 的绑定的定义。 (似乎也没有包含在提供的信息中?)
有关协议映射的更多信息,请参阅:https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/protocolmapping
除此之外,您的要求也可能是改用此配置:
<wsHttpBinding>
...
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
...
</wsHttpBinding>
这与您是想使用 SOAP 消息 encryption/signing 确保消息的完整性还是对 HTTPS 提供的完整性感到满意有关。
根据您问题中 linked 的文章,您甚至可以使用 basicHttpBinding 而不是 wsHttpBinding 并使用安全模式设置为 Transport 并将传输部分的 clientCredentialType 属性设置为 Basic 例如,
<basicHttpBinding>
...
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
...
</basicHttpBinding>
有关不同安全模式的详细信息,请参阅:https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/wcf/security-of-wshttpbinding
最后,我也不建议保留 serviceDebug 设置,该设置允许您将异常详细信息包含在生产环境中。 (当然这又取决于您的要求)