我有创建 ASP.net/WinForms 应用程序的经验,现在我想通过创建一个简单的任务管理器项目来学习 WCF。
提前感谢您阅读传入的文本块。我的问题更多是设计问题,而不是实际的编码问题。
我的目标如下:
- 创建一个 Web 服务(使用 WCF),其目的是管理任务/待办事项列表
- Web 服务将允许用户注册帐户、创建新的待办事项列表、与其他用户共享待办事项列表等
- 在 Web 服务正常运行并实现所有内容后,我希望能够在其之上放置一个 ASP.NET 网站并将 Web 服务用于后端
目前我有以下内容:
- 1 个托管 Web 服务的控制台应用程序
- 1 个控制台应用程序(客户端)用于调用 Web 服务(我以这种方式测试我的 Web 服务)
Web 服务应用程序具有以下配置文件(希望我粘贴成功):
<?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);
}
我试图完成的是以下内容:
- 提供不安全的端点;客户可以调用它并注册一个帐户。
- 提供一个安全端点(我使用带有自定义 UserNamePasswordValidator 的 UserName 身份验证),用户可以通过该端点“登录”并调用所有操作。
我的软件中的这两个东西现在都可以工作。我可以通过不安全的端点注册新帐户,并且可以通过在客户端中提供正确的 ClientCredentials 来调用安全端点。
我的问题如下:
据我了解,通过使用 UserName 身份验证,每次客户端调用 Web 服务方法时都会调用我的自定义验证器中的 Validation 方法(这意味着每次都会运行 DB 查询来检查凭据,而不是网站您登录一次,直到您的会话到期)。以这种方式做事有什么根本错误吗?
我想到了另一种可能的方法来管理它(并且以某种方式模拟网站的工作方式):
- 仅将安全端点(用户名身份验证)用于类似于“登录”的操作
- 如果凭据正确,我将创建一个新的 GUID,将其保存在内存中并在用户名和该 guid 之间建立关联。
- 那么所有操作都不需要用户名身份验证,但会有一个附加参数(GUID):如果 GUID 在内存中并与用户相关联,则允许该操作
- 注销操作会破坏内存中的 GUID。
- 我会假设我可以在此之上使用 SSL,这样 GUID 就不会被明文发送
- 这是否违背了 Web 服务安全的目的,而我只是想重新发明轮子?
哪种方法会更好?为什么?
更新:添加了错误的配置文件。它来自客户端而不是 Web 服务。现在添加了正确的。