![](/img/trans.png)
[英]WCF authentication custom username and password validator for multiple users
[英]WCF and custom Authentication (username/password)
我有 Windows Forms 客戶端通過 Internet 連接到 WCF 服務。 WCF 服務托管在 Windows 服務中,該服務在專用 Windows 帳戶下運行。 我想通過檢查用戶名+密碼對來針對數據庫驗證客戶端。
為了避免數百種方法,例如:
public int Add(string User, string Password, int A, int B)
我使用以下指南覆蓋UserNamePasswordValidator
class:
http://blog.clauskonrad.net/2011/03/how-to-wcf-and-custom-authentication.html
我的自定義身份驗證器 class 與示例匹配
class UsernameAuthentication : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//Will be checked against database
var ok = (userName == "Ole") && (password == "Pwd");
if (ok == false)
throw new AuthenticationException("u/p does not match");
}
}
我的服務器配置是:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<system.serviceModel>
<services>
<service name="TestWCFCustomAuth.CalculatorService" behaviorConfiguration="customCred">
<endpoint address="CalcSvc"
binding="netTcpBinding"
bindingConfiguration="secUP"
contract="ServiceInterface.ICalculatorService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="ServiceInterface.ICalculatorService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:81/"/>
<add baseAddress="net.tcp://localhost:82/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="secUP">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="customCred">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceCredentials>
<!--Service identity + encryption certificate-->
<serviceCertificate findValue="SHKIService" storeLocation="LocalMachine" storeName="Root" x509FindType="FindBySubjectName"/>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="TestWCFCustomAuth.UsernameAuthentication, TestWCFCustomAuth" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
客戶端是自動生成的:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_ICalculatorService">
<security mode="Message">
<transport sslProtocols="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</netTcpBinding>
<wsHttpBinding>
<binding name="MetadataExchangeHttpBinding_ICalculatorService">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:82/CalcSvc" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_ICalculatorService" contract="ServiceReference1.ICalculatorService"
name="NetTcpBinding_ICalculatorService">
<identity>
<certificate encodedValue="AwAAAAEAAAAUAAAA5Miz/2tl3pOxgQepIM62wzcAU+8gAAAAAQAAAK0BAAAwggGpMIIBCqADAgECAgkArWjRy0f0w98wCgYIKoZIzj0EAwIwFjEUMBIGA1UEAxMLU0hLSVNlcnZpY2UwHhcNMjEwMzI5MjEzNjUwWhcNMjYwMzI5MjEzNjUwWjAWMRQwEgYDVQQDEwtTSEtJU2VydmljZTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAXE/ZelSAJ7+qjUTECzz2ZHFHTd6KtYsrbgdvBw3Xqt/G9R4IO01Rvxltir7FMfHzLgzsa4LdLkY3yAk/4rOqTPqAXY/sd/TpZOOB7ntZx02BEUvNiKouVu+yzIBMQxyW4aGZGOftiSOA28VKxNnaARN97/IoYyO0FhN+4vlKaPlTGFQMAoGCCqGSM49BAMCA4GMADCBiAJCAa88D2F5LuEFF0BL2+Vn1xIGSrjLo1YpiJk0DNJEbF0OOzH+xuKk/8H4yjQGO/yMmI8/pQWeU36Bu/D2xxJ0XqvtAkIA9udnx+h7lAsAYOtFMT12qHkVHInGWTzGHjNF0nrOldURa7X8B+tDeYrDJGBD+/9R2E4koJeGb0ubAmUl4Hrwyik=" />
</identity>
</endpoint>
<endpoint address="http://localhost:81/mex" binding="wsHttpBinding"
bindingConfiguration="MetadataExchangeHttpBinding_ICalculatorService"
contract="ServiceReference1.ICalculatorService" name="MetadataExchangeHttpBinding_ICalculatorService" />
</client>
</system.serviceModel>
</configuration>
我做了一個自簽名證書,並把它導入到根目錄,所以證書配置也OK。
測試客戶端代碼是:
var client = new CalculatorServiceClient("NetTcpBinding_ICalculatorService");
client.ClientCredentials.UserName.UserName = "Ole";
client.ClientCredentials.UserName.Password = "Pwd";
var res = client.Add(1, 2);
Console.WriteLine("Result: {0}", res);
盡管我的代碼與指南幾乎相同,但出現錯誤:
System.ServiceModel.Security.SecurityNegotiationException: 'The caller was not authenticated by the service.'
Inner Exception:
FaultException: The request for security token could not be satisfied because authentication failed.
我搜索了幾天的答案並嘗試了許多其他配置。 我最好的猜測是幕后發生了其他類型的身份驗證? 如果是這樣 - 我該如何禁用它?
官方文檔中有完整的demo,使用用戶名密碼驗證,也有證書驗證。 您只需要按照教程中的步驟操作即可成功運行。 你可以參考參考。
我缺少的步驟如下:
要向帳戶授予對私鑰的權限,可以使用 mmc 的證書管理單元。 可以啟動mms.exe,在“文件”菜單中選擇“添加/刪除管理單元”,選擇“證書”管理單元,然后選擇本地計算機的“計算機帳戶”。 然后應該 select 個人存儲的 SSL 證書,然后使用上下文菜單“管理私鑰...”。
運行客戶端應用程序的計算機需要在CurrentUser\Trusted People
存儲中擁有證書(即使客戶端和服務器在同一台計算機上運行)。 因此,我使用上一步中的 mmc 工具將沒有私鑰的證書導出到文件中,然后將該文件中的證書導入CurrentUser\Trusted People
存儲。 我想我必須將此文件包含在我客戶的安裝 package 中。
這一次我使用makecert.exe
工具創建證書,如 @Theobald Du 提供的 msdn 參考中所建議的命令是:
makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=<I used server's IP address> -sky exchange -pe
PS 另外我在那台機器上缺少 makecert.exe,所以我從microsoft下載了 Microsoft SDK
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.