WCF之添加自定义用户名密码认证
1.创建WCF服务应用以及调用客户端(请自行google)。
2.创建X509证书
cmd 进入 C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\
makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=JJWcfService -sky exchange -pe
下面是各种参数的介绍
属性 |
解析 |
-sr |
指定的证书存储区中的注册表位置。 |
-ss |
指定证书存储的位置。 |
-a |
指定相关的算法,可以选择 MD5 算法或者 SHA1算法 |
-n |
指定证书的名称。该名称遵循X.500命名标准。简单例子如 "CN=MyName" 格式,如果没有指定/n开关,证书默认的名称是"Joe's Software Emporium"。 |
-sky |
证书键类型。可以设置为 exchange 或者 signature。 |
-pe |
证书可导出 |
出现succeeded说明证书创建成功。
查看证书:
1.win+r==>mmc==>确定 打开控制台
2.文件==>添加/删除管理单元==>证书==>添加==>我的用户账户==>完成==>添加==>计算机账户==>下一步==>完成==>确定
导出证书:
此处务必选择是,导出私钥,设置密码导出即可,
证书(本地计算机)==>受信任的根证书颁发机构==>证书==>所有任务==>导入==>下一步==>选择证书==>输入密码==>下一步==>完成
3.为WCF服务添加自定义验证 (添加一个继承UserNamePasswordValidator的类并重写Validate)
1 // 自定义的用户名/密码验证类 2 /// </summary> 3 public class CustomNamePasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator 4 { 5 /// <summary> 6 /// 验证指定的用户名和密码 7 /// </summary> 8 /// <param name="userName">要验证的用户名</param> 9 /// <param name="password">要验证的密码</param> 10 public override void Validate(string userName, string password) 11 { 12 if (!(userName == "xxx" && password == "xxx")) 13 { 14 throw new FaultException("用户名或密码不正确"); 15 } 16 } 17 }
4.为WCF宿主添加如下Config配置
1 <system.serviceModel> 2 <services> 3 <!--name - 提供服务的类名--> 4 <!--behaviorConfiguration - 指定相关的行为配置--> 5 <service name="ZhiHeng.JinJiBox.Service.Api" behaviorConfiguration="SecurityBehavior"> 6 <!--address - 服务地址--> 7 <!--binding - 通信方式--> 8 <!--contract - 服务契约--> 9 <endpoint address="" binding="wsHttpBinding" contract="ZhiHeng.JinJiBox.Service.IApi" bindingConfiguration="SecurityBindingConfiguration" /> 10 <host> 11 <baseAddresses> 12 <add baseAddress="http://localhost:8000/CardOper" /> 13 </baseAddresses> 14 </host> 15 </service> 16 </services> 17 <behaviors> 18 <serviceBehaviors> 19 <behavior name="SecurityBehavior"> 20 <!--httpGetEnabled - 指示是否发布服务元数据以便使用 HTTP/GET 请求进行检索,如果发布 WSDL,则为 true,否则为 false,默认值为 false--> 21 <serviceMetadata httpGetEnabled="true" /> 22 <serviceDebug includeExceptionDetailInFaults="true"/> 23 <serviceCredentials> 24 <!--userNamePasswordValidationMode - 以用户名/密码模式来进行验证的方法--> 25 <!--UserNamePasswordValidationMode.Windows - 用户名映射到 Windows 用户--> 26 <!--UserNamePasswordValidationMode.MembershipProvider - 提供基于已配置的 MembershipProvider 的密码验证--> 27 <!--UserNamePasswordValidationMode.Custom - 基于已配置的自定义 UsernamePasswordValidator 的自定义身份验证--> 28 <!--customUserNamePasswordValidatorType - 所使用的自定义用户名密码验证程序的类型--> 29 <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="ZhiHeng.JinJiBox.Service.CustomNamePasswordValidator, ZhiHeng.JinJiBox.Service" /> 30 <!--findValue - 指定要在 X.509 证书存储区中搜索的值--> 31 <!--storeLocation - 指定客户端可用于验证服务器证书的证书存储区位置(LocalMachine - 分配给本地计算机的 X.509 证书存储区;CurrentUser - 当前用户使用的 X.509 证书存储区)--> 32 <!--storeName - 要打开的 X.509 证书存储区的名称(参看:StoreName枚举。AddressBook, AuthRoot, CertificateAuthority, Disallowed, My, Root, TrustedPeople, TrustedPublisher)--> 33 <!--x509FindType - 要执行的 X.509 搜索的类型(参看:X509FindType枚举)--> 34 <serviceCertificate findValue="JJWcfService" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> 35 </serviceCredentials> 36 </behavior> 37 </serviceBehaviors> 38 </behaviors> 39 <bindings> 40 <wsHttpBinding> 41 <binding name="SecurityBindingConfiguration"> 42 <security> 43 <!--clientCredentialType - 客户端用以进行身份验证的凭据的类型,默认值 UserName --> 44 <!--BasicHttpMessageCredentialType.UserName - 使用用户名凭据对客户端进行身份验证--> 45 <!--BasicHttpMessageCredentialType.Certificate - 使用证书对客户端进行身份验证--> 46 <message clientCredentialType="UserName" /> 47 </security> 48 </binding> 49 </wsHttpBinding> 50 </bindings> 51 </system.serviceModel>
启动WCF服务端。
5.生成WCF客户端Config配置
vs==>工具==>外部工具==>添加==>标题SvcUtil,命令C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\SvcUtil.exe,初始目录$(SolutionDir)==>应用,确定==>工具==>SvcUtil==>参数输入WCF的服务地址,不出意外会在项目跟目录生成2个文件,将代理文件拷贝到WCF客户端,将配置文件拷贝到客户端配置文件中
1 <system.serviceModel> 2 <bindings> 3 <wsHttpBinding> 4 <binding name="WSHttpBinding_IApi" closeTimeout="00:01:00" openTimeout="00:01:00" 5 receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" 6 transactionFlow="false" hostNameComparisonMode="StrongWildcard" 7 maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 8 messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" 9 allowCookies="false"> 10 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 11 maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 12 <reliableSession ordered="true" inactivityTimeout="00:10:00" 13 enabled="false" /> 14 <security mode="Message"> 15 <transport clientCredentialType="Windows" proxyCredentialType="None" 16 realm="" /> 17 <message clientCredentialType="UserName" negotiateServiceCredential="true" 18 algorithmSuite="Default" establishSecurityContext="true" /> 19 </security> 20 </binding> 21 </wsHttpBinding> 22 </bindings> 23 <client> 24 <endpoint address="http://localhost:8000/CardOper" binding="wsHttpBinding" 25 bindingConfiguration="WSHttpBinding_IApi" contract="IApi" 26 name="WSHttpBinding_IApi"> 27 <identity> 28 <certificate encodedValue="AwAAAAEAAAAUAAAAvDJSUOU7j3OZw58oadeaOQ2hFwwgAAAAAQAAAAMCAAAwggH/MIIBaKADAgECAhAsiRVKHUl5gk8EfX3h8Nl8MA0GCSqGSIb3DQEBBAUAMBcxFTATBgNVBAMTDEpKV2NmU2VydmljZTAeFw0xNjA4MTYwNjQ3MDdaFw0zOTEyMzEyMzU5NTlaMBcxFTATBgNVBAMTDEpKV2NmU2VydmljZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAudUXIgHlGJi7R+DJBxqfB9EldfxTk2uhRlc/miG+UEG2049rZzyg8C4buGq6czimSWw+3qdRC5ssBCFvutgsspGD4Yfnthycc9FJJrnJ7XMEi+YuvBy6dhx3VvnqYD2V8lYARbzFcjBJZPJCTfVibR9Q2ztR3fCUOaCax8JqA08CAwEAAaNMMEowSAYDVR0BBEEwP4AQbxiagPbpXbaqlELymH5aDKEZMBcxFTATBgNVBAMTDEpKV2NmU2VydmljZYIQLIkVSh1JeYJPBH194fDZfDANBgkqhkiG9w0BAQQFAAOBgQAnouchd9o4q3fR212HD4aiD5iXXQv6o7VMY4TZPn/+UDaLXEZVB5mbuCh0vnlU2zIaJCN9LuQiQ9/MyjuoTKA2lAMup+hMw5F0bnjeWOdwD6shKBqnLlY44hufbVx0U2rN8n9Yay9oCYSzBnM3WKNXIWc1TeGBJvnpDBnMqqvNeA==" /> 29 </identity> 30 31 </endpoint> 32 </client> 33 </system.serviceModel>
6 客户端调用
1 using (var proxy = new Api()) 2 { 3 //此出进行验证 4 proxy.ClientCredentials.UserName.UserName = “xxx”; 5 proxy.ClientCredentials.UserName.Password = "xxx"; 6 7 //在下面调用你的WCF方法 8 proxy.SayHello("Vis"); 9 }
参考:
http://www.cnblogs.com/leeolevis/archive/2011/05/17/2048710.html
http://www.cnblogs.com/wuhuacong/archive/2011/09/29/2195528.html