使用WCF服务验证ASP.NET Web应用程序

时间:2022-11-16 20:13:24

Background

背景

I have an ASP.NET web application that interacts with WCF services. The web application and the WCF services are under my control. The ASP.NET web application uses a custom implementation of the ASP.NET Membership Provider Model (with passwords stored in hashed form) to authenticate users who log in to the web application. Both the ASP.NET web application and WCF services have access to the same membership database.

我有一个与WCF服务交互的ASP.NET Web应用程序。 Web应用程序和WCF服务由我控制。 ASP.NET Web应用程序使用ASP.NET成员资格提供程序模型的自定义实现(密码以散列形式存储)来验证登录Web应用程序的用户。 ASP.NET Web应用程序和WCF服务都可以访问相同的成员资格数据库。

Since the users will supply their password only once, and I don't want to have to store their passwords anywhere or annoy them by repeatedly asking them to resupply their password, I need an appropriate mechanism to authenticate the users with the WCF services.

由于用户只提供一次密码,并且我不想将密码存储在任何地方或者通过反复要求他们重新提供密码来惹恼他们,我需要一种适当的机制来使用WCF服务对用户进行身份验证。

Based on other questions and answers I have seen, I am considering a sort of "login session" approach, where a login session will be created in the custom membership database when the user initially logs in to the web application, with the login session identified by a GUID, and automatically expired after a period of inactivity. The login session GUID will be "remembered" by the web application for each logged in user (either stored in the Forms Authentication Ticket or in the session).

基于我看到的其他问题和答案,我正在考虑一种“登录会话”方法,当用户最初登录到Web应用程序时,将在自定义成员资格数据库中创建登录会话,并确定登录会话通过GUID,并在一段时间不活动后自动过期。 Web应用程序将为每个登录用户“记住”登录会话GUID(存储在Forms Authentication Ticket或会话中)。

The WCF service will also provide its own login operation accepting a user name and password and returning a login session GUID as described above.

WCF服务还将提供其自己的登录操作,接受用户名和密码,并返回如上所述的登录会话GUID。

The WCF service would then accept the login session GUID for all other operations, and verify that the GUID represents a valid login session that has not expired before allowing the operation to proceed.

然后,WCF服务将接受所有其他操作的登录会话GUID,并在允许操作继续之前验证GUID表示尚未过期的有效登录会话。

I have done quite a bit of background reading on this, and there is a lot of material on straightforward use of the UserName client credential type, but this would require the web application to remember the user's password, which doesn't seem like a great idea to me.

我已经做了相当多的背景阅读,并且有很多关于直接使用UserName客户端凭据类型的材料,但这需要Web应用程序记住用户的密码,这看起来不是很好我的想法。

I've done some research and found material on MSDN, but this seems like a lot of effort to implement what (to me at least) seems like a pretty common usage scenario.

我已经完成了一些研究,并在MSDN上找到了材料,但这似乎是很多努力来实现(至少对我来说)似乎是一种非常常见的使用场景。

How to: Create a Custom Token

如何:创建自定义标记

Question

Is the general approach of the "login session" described above reasonable?
If so, what is the best way to achieve it?
If not, can you suggest an alternative?

上面描述的“登录会话”的一般方法是否合理?如果是这样,实现它的最佳方法是什么?如果没有,你能建议一个替代方案吗?

6 个解决方案

#1


2  

This is a very reasonable approach.

这是一种非常合理的方法。

To do this you setup your service endpoint and configure it with your custom membership provider (You can do the same with SQL membership provider, it doesn't require a custom one).

为此,您需要设置服务端点并使用自定义成员资格提供程序对其进行配置(您可以对SQL成员资格提供程序执行相同操作,但不需要自定义成员资格提供程序)。

On the web application you set up the Authenticate event of the Login control to instantiate a new service proxy and set the username/password in the ClientCredentials in the proxy.

在Web应用程序上,您设置Login控件的Authenticate事件以实例化新服务代理,并在代理中的ClientCredentials中设置用户名/密码。

Now when you make the call to the Service through the proxy WCF will pass these credentials through the secure channel to the service and use them for authentication.

现在,当您通过代理调用服务时,WCF会将这些凭据通过安全通道传递给服务并使用它们进行身份验证。

Now you simply need to store the proxy in session and use it for future access to the service as it has the channel state and a private key.

现在,您只需将代理存储在会话中,并将其用于将来访问服务,因为它具有通道状态和私钥。

protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
    bool Authenticated = false;
    try
    {
        MyServiceClient proxy = new MyServiceClient("MyServiceEndpoint");
        proxy.ClientCredentials.UserName.UserName = LoginControl.UserName;
        proxy.ClientCredentials.UserName.Password = LoginControl.Password;

        //It doesn't really matter what is called or what it does because 
        //Membership Provider for the Service does the authentication.
        string retval = proxy.login("Logging in"); 

        //Now that channel is established the proxy needs to be kept
        //since it contains the channel state which includes a private key
        Session["MyServiceProxy"] = proxy;  
        Authenticated = true;
    }
    catch (Exception ex)
    {
        //Login Error...
    }
    e.Authenticated = Authenticated;
}

#2


1  

There are two possible solutions I can think of:

我能想到两种可能的解决方案:

Firstly, if the WCF service is an internal service, the web application can then send the name of the user that is asking for the data with each request.

首先,如果WCF服务是内部服务,则Web应用程序可以随每个请求发送要求数据的用户的名称。

The second is that you store the user name and hash of the password (or actual password) somewhere. Either in the session state or in the user cookie (a session cookie stored in memory passed to the user over https). Then pass the user name and password to the WCF service with each request.

第二个是你在某处存储用户名和密码(或实际密码)的哈希值。在会话状态或用户cookie中(存储在内存中的会话cookie通过https传递给用户)。然后将用户名和密码传递给每个请求的WCF服务。

#3


1  

See my answer on Storing password in forms authentication cookie - ASP.NET and WCF calls for a solution that does not require storing passwords.

请参阅我在表单身份验证cookie中存储密码的答案 - ASP.NET和WCF调用不需要存储密码的解决方案。

#4


1  

Thanks to everyone for your input. I've settled on an approach (at least for now). It's fairly simple and works well for my purposes.

感谢大家的投入。我已经确定了一种方法(至少目前为止)。它非常简单,适用于我的目的。

Using the "UserName" clientCredentialType, and an explicit service login method that returns a security token (token generation details omitted for brevity), the service client can decide whether to pass the genuine password as the password property on the client credentials or the security token instead (obtained from the login method). If the client is a web application the security token could be stored in the forms authentication ticket, or the session, or wherever.

使用“UserName”clientCredentialType和返回安全令牌的显式服务登录方法(为简洁起见省略了令牌生成详细信息),服务客户端可以决定是否将正版密码作为客户端凭据或安全令牌上的密码属性传递相反(从登录方法获得)。如果客户端是Web应用程序,则安全令牌可以存储在表单身份验证票证,会话或任何位置。

Using the "Custom" userNamePasswordValidationMode and a custom implementation of UserNamePasswordValidator, the validator inspects the password to determine whether it is a valid security token or a password - if it's a password the client credentials are authenticated against the user store (SQL Server database), and if it's a security token then it is checked to ensure it is valid, hasn't expired, and belongs to the user name.

使用“Custom”userNamePasswordValidationMode和UserNamePasswordValidator的自定义实现,验证器检查密码以确定它是有效的安全令牌还是密码 - 如果是密码,则客户端凭据将针对用户存储(SQL Server数据库)进行身份验证,如果它是安全令牌,则检查它以确保它有效,尚未过期,并且属于用户名。

#5


0  

I would suggest to take a look at Geneva which is aimed at solving scenarios as yours. The basic idea is to require the same security token, by mean of an HttpModule, for both the WCF services and the ASP site. The token will be release after authenticating against your membership database and may contain useful info (claims) on the user.

我建议你看看日内瓦,它旨在解决你的情景。基本思想是通过HttpModule为WCF服务和ASP站点要求相同的安全令牌。该令牌将在对您的成员资格数据库进行身份验证后发布,并且可能包含对用户的有用信息(声明)。

For an intro you may read Bustamante's article.

有关介绍,您可以阅读Bustamante的文章。

#6


0  

Microsoft has a WCF service that you can use to authenticate users with ASP.NET Membership.

Microsoft有一个WCF服务,您可以使用该服务来验证具有ASP.NET成员身份的用户。

The code is actually built into the framework - you just need to create a .svc file to use it.

代码实际上构建在框架中 - 您只需要创建一个.svc文件来使用它。

http://msdn.microsoft.com/en-us/library/bb398990.aspx

http://msdn.microsoft.com/en-us/library/bb398990.aspx

#1


2  

This is a very reasonable approach.

这是一种非常合理的方法。

To do this you setup your service endpoint and configure it with your custom membership provider (You can do the same with SQL membership provider, it doesn't require a custom one).

为此,您需要设置服务端点并使用自定义成员资格提供程序对其进行配置(您可以对SQL成员资格提供程序执行相同操作,但不需要自定义成员资格提供程序)。

On the web application you set up the Authenticate event of the Login control to instantiate a new service proxy and set the username/password in the ClientCredentials in the proxy.

在Web应用程序上,您设置Login控件的Authenticate事件以实例化新服务代理,并在代理中的ClientCredentials中设置用户名/密码。

Now when you make the call to the Service through the proxy WCF will pass these credentials through the secure channel to the service and use them for authentication.

现在,当您通过代理调用服务时,WCF会将这些凭据通过安全通道传递给服务并使用它们进行身份验证。

Now you simply need to store the proxy in session and use it for future access to the service as it has the channel state and a private key.

现在,您只需将代理存储在会话中,并将其用于将来访问服务,因为它具有通道状态和私钥。

protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
    bool Authenticated = false;
    try
    {
        MyServiceClient proxy = new MyServiceClient("MyServiceEndpoint");
        proxy.ClientCredentials.UserName.UserName = LoginControl.UserName;
        proxy.ClientCredentials.UserName.Password = LoginControl.Password;

        //It doesn't really matter what is called or what it does because 
        //Membership Provider for the Service does the authentication.
        string retval = proxy.login("Logging in"); 

        //Now that channel is established the proxy needs to be kept
        //since it contains the channel state which includes a private key
        Session["MyServiceProxy"] = proxy;  
        Authenticated = true;
    }
    catch (Exception ex)
    {
        //Login Error...
    }
    e.Authenticated = Authenticated;
}

#2


1  

There are two possible solutions I can think of:

我能想到两种可能的解决方案:

Firstly, if the WCF service is an internal service, the web application can then send the name of the user that is asking for the data with each request.

首先,如果WCF服务是内部服务,则Web应用程序可以随每个请求发送要求数据的用户的名称。

The second is that you store the user name and hash of the password (or actual password) somewhere. Either in the session state or in the user cookie (a session cookie stored in memory passed to the user over https). Then pass the user name and password to the WCF service with each request.

第二个是你在某处存储用户名和密码(或实际密码)的哈希值。在会话状态或用户cookie中(存储在内存中的会话cookie通过https传递给用户)。然后将用户名和密码传递给每个请求的WCF服务。

#3


1  

See my answer on Storing password in forms authentication cookie - ASP.NET and WCF calls for a solution that does not require storing passwords.

请参阅我在表单身份验证cookie中存储密码的答案 - ASP.NET和WCF调用不需要存储密码的解决方案。

#4


1  

Thanks to everyone for your input. I've settled on an approach (at least for now). It's fairly simple and works well for my purposes.

感谢大家的投入。我已经确定了一种方法(至少目前为止)。它非常简单,适用于我的目的。

Using the "UserName" clientCredentialType, and an explicit service login method that returns a security token (token generation details omitted for brevity), the service client can decide whether to pass the genuine password as the password property on the client credentials or the security token instead (obtained from the login method). If the client is a web application the security token could be stored in the forms authentication ticket, or the session, or wherever.

使用“UserName”clientCredentialType和返回安全令牌的显式服务登录方法(为简洁起见省略了令牌生成详细信息),服务客户端可以决定是否将正版密码作为客户端凭据或安全令牌上的密码属性传递相反(从登录方法获得)。如果客户端是Web应用程序,则安全令牌可以存储在表单身份验证票证,会话或任何位置。

Using the "Custom" userNamePasswordValidationMode and a custom implementation of UserNamePasswordValidator, the validator inspects the password to determine whether it is a valid security token or a password - if it's a password the client credentials are authenticated against the user store (SQL Server database), and if it's a security token then it is checked to ensure it is valid, hasn't expired, and belongs to the user name.

使用“Custom”userNamePasswordValidationMode和UserNamePasswordValidator的自定义实现,验证器检查密码以确定它是有效的安全令牌还是密码 - 如果是密码,则客户端凭据将针对用户存储(SQL Server数据库)进行身份验证,如果它是安全令牌,则检查它以确保它有效,尚未过期,并且属于用户名。

#5


0  

I would suggest to take a look at Geneva which is aimed at solving scenarios as yours. The basic idea is to require the same security token, by mean of an HttpModule, for both the WCF services and the ASP site. The token will be release after authenticating against your membership database and may contain useful info (claims) on the user.

我建议你看看日内瓦,它旨在解决你的情景。基本思想是通过HttpModule为WCF服务和ASP站点要求相同的安全令牌。该令牌将在对您的成员资格数据库进行身份验证后发布,并且可能包含对用户的有用信息(声明)。

For an intro you may read Bustamante's article.

有关介绍,您可以阅读Bustamante的文章。

#6


0  

Microsoft has a WCF service that you can use to authenticate users with ASP.NET Membership.

Microsoft有一个WCF服务,您可以使用该服务来验证具有ASP.NET成员身份的用户。

The code is actually built into the framework - you just need to create a .svc file to use it.

代码实际上构建在框架中 - 您只需要创建一个.svc文件来使用它。

http://msdn.microsoft.com/en-us/library/bb398990.aspx

http://msdn.microsoft.com/en-us/library/bb398990.aspx