我有创建ASP.net/WinForms应用程序的经验,我想通过创建一个简单的任务管理器项目来学习WCF。
提前感谢您阅读传入的文本块。我的问题更多的是设计而不是实际的编码问题。
我的目标如下:
目前我有以下内容:
Web Service应用程序具有以下配置文件(希望我将其粘贴好):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="Tasker_Server.Properties.Settings.TaskerConnectionString"
connectionString="Data Source=PROPHET\SQLEXPRESS;Initial Catalog=Tasker;Persist Security Info=True;User ID=sa;Password=stf"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.serviceModel>
<services>
<service name="Tasker_Server.TaskerService" behaviorConfiguration="TaskerServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/TaskerTest/Service" />
</baseAddresses>
</host>
<endpoint name="login" address="username" binding="wsHttpBinding"
bindingConfiguration="Binding1"
contract="Tasker_Server.ITasker" />
<endpoint name="reg" address="reg" binding="wsHttpBinding"
bindingConfiguration="Binding2"
contract="Tasker_Server.Contracts.IRegister" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="Binding1" receiveTimeout="00:20:00">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
<binding name="Binding2">
<security mode="None">
<transport clientCredentialType="None" />
<message establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="TaskerServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Tasker_Server.CustomValidator, Tasker_Server" />
<serviceCertificate findValue="localhost"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
我就像这样启动Web服务:
ServiceHost selfHost = new ServiceHost(typeof(TaskerService));
try {
selfHost.Open();
Console.WriteLine("Service is up... (press <ENTER> to terminate)");
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce) {
Console.WriteLine("Exception: {0}", ce.Message);
Console.ReadLine();
selfHost.Abort();
}
目前我只有两份合同:
[ServiceContract(Namespace="http://Tasker_Server")]
public interface ITasker {
[OperationContract]
string CheckCredentials(string username, string password);
}
和
[ServiceContract(Namespace="http://Tasker_Register")]
public interface IRegister {
[OperationContract]
string RegisterUser(string username, string password, string email);
}
我试图完成的是以下内容:
我的软件中的这些东西现在都可以使用。我可以通过不安全的端点注册一个新帐户,我可以通过在客户端提供正确的ClientCredentials来调用安全端点。
我的问题如下:
据我所知,通过使用UserName身份验证,每次客户端调用Web Service方法时,都会调用自定义验证程序中的Validation方法(这意味着每次都会运行数据库查询来检查凭据而不是您登录一次直到会话到期的网站)。以这种方式做事有什么根本性的错误吗?
我想到了另一种可能的方法来管理它(并以某种方式模拟网站的运作方式):
哪种方法会更好?为什么?
更新:添加了错误的配置文件。它来自客户端而不是Web服务。现在添加了正确的。
答案 0 :(得分:2)
你使用guid的方法很好。请参阅其他问题WCF ticket base authentication并提及帖子
更新:方法比较。
第一种方法的好处是无状态/无会话的个别操作。客户端和服务都不需要记住先前身份验证调用的详细信息。但是,如果同一个客户端进行多次呼叫,最好记住故障单,而不是每次都记住并发送用户名和密码。 如果您担心重复调用数据库,可以缓存一段时间(例如30分钟) 用户名和密码(或更好的哈希值),并在进行数据库调用之前比较缓存字典中新请求的详细信息。
第二种方法需要在客户端保持状态(即票证),因此有点复杂。但它更安全,因为您不需要在整个会话期间记住用户名和密码。对于您的方案,我更喜欢票务方法。
顺便说一下,登录后我仍然建议使用https(通常性能损失不是必需的)但它会阻止网络嗅探器窃取故障单并使用它来代替用户进行一些恶意操作。
答案 1 :(得分:2)
2是一个合理的想法。它叫做Window Identity Framework。
与您建议的唯一真正区别在于,在联合安全模型中,您将身份验证与应用程序分开。在WIF中,您向发出令牌(您的GUID)的受信任机构进行身份验证。令牌内的加密是一组声明(允许的操作)。客户端将令牌作为其WCF调用的一部分传递,声明转移到安全原则,突然您的应用程序在没有任何WCF知识的情况下执行基于角色的安全性。
WIF的缺点是它很复杂,可能需要相当多的加速时间。
WIF的优势在于它由安全专家撰写。如果您实际构建的是处理金钱或敏感数据的商业应用程序,您应该仅仅因为这个原因使用WIF。
这是一个older article,但这是一个很好的动机。然后是MSDN。
答案 2 :(得分:0)
你没有在WCF中实现你想要的using sessions吗?