WCF 4.0 REST 用户名密码认证

7
我一直在为WCF 4.0 RESTful服务中的用户名/密码身份验证/授权问题而苦苦挣扎,使用了ASP.Net成员资格/角色提供程序。花费了两天时间试图找到大多数人都同意的东西,但我还是放弃了。很多混乱似乎是因为WCF 4.0的具体信息很少。
以下是需要回答的问题:
1.是否有权威观点认为WCF 4.0 + REST是一个好主意?
2.概述此过程的通常接受步骤(或链接)。
3.提供完成此操作所需的完整代码示例。
编辑:奖励任何人能够提供使用VS 2010中的WCF服务应用程序模板,实现RESTfull WCF 4.0服务的用户名/密码身份验证和授权的完整示例(甚至只是一个链接)。

那么IIS NT身份验证不是可行的选择吗? - Jeremy
你可以通过 ASP.net Web 应用程序项目公开 WCF 合同,并可能在 web.config 中应用 ASP.net 身份验证。 - Jeremy
那不需要使用SOAP头吗?使用Membership和Roleproviders并不是真正的问题。问题在于将所有东西连接在一起。 - NVM
创建一个空的 ASP.net Web 应用程序,添加一个 svc 并更改您的 web.config 以适应。您可能会感到惊喜。例如:https://dev59.com/7FTTa4cB1Zd3GeqPqC0T - Jeremy
抱歉,我不理解。它将首先如何进行身份验证?这将是Restful吗? - NVM
你的服务的目的是什么,将有哪些应用程序使用它? - Florin Dumitrescu
4个回答

10

我认为你的问题的答案取决于你的服务的目的和将要使用它的应用程序类型。

如果你有一个现有的ASP .Net应用程序,并且希望将其部分功能公开为RESTful服务,以便你可以在客户端使用AJAX进行消费,那么WCF可能不是最佳选择。在这种情况下,你已经在Web应用程序中拥有一个身份验证用户,并且希望在AJAX调用期间传播该身份验证。实际上,实现这个很简单。

ASP .Net Forms身份验证基于身份验证Cookie,在成功登录后生成并传递给浏览器。从浏览器向与你的应用程序相同域名的任何URL发出的每个调用也将包含身份验证Cookie。在ASP .Net MVC中,你可以将服务方法简单地实现为需要授权的控制器操作,所有事情都将在幕后自动进行。

在经典的ASP .Net中,你可以使用PageMethods来实现你的服务方法,Cookie也会在幕后发送并验证(PageMethods示例这里这里)。

另一方面,如果你的服务将在浏览器之外被消费(例如来自桌面或移动应用程序),那么WCF可能确实是实现该服务的正确工具。但是,ASP .Net Forms身份验证不是实现安全性的最佳选择。 REST服务的主要目的是简单性,以便客户端可以轻松地在每个平台上实现,而基于Cookie的ASP .Net Forms身份验证机制并不是最直接的。

一个专为Web服务上下文中的用户身份验证构建的协议是OAuth。其第二版仍处于草案阶段(规范在此处),但是很可能这是你想要使用的版本,因为它比OAuth 1.0更简单。 Facebook已经通过OAuth 2.0实现了其API身份验证(详细信息在此处),你可能会想要查看他们的实现作为灵感。

除了用户身份验证外,OAuth还确保使用应用程序(服务客户端)身份验证,并确保用户永远不会直接在客户端应用程序中输入其凭据。如果这比你实际需要的多,那么你可以创建一个灵感来自OAuth 2.0的自定义实现。

首先,你需要通过HTTPS公开你的服务,以便服务和客户端之间的所有通信都被加密。其次,你需要在服务中创建一个类似以下的登录方法:

string Login(string user, string password);

成功登录后,上述方法将返回一个身份验证令牌。该身份验证令牌将用于并在所有其他方法上进行验证。例如:

Employee[] GetAllEmployees(string authToken)
{
  // verify token here

  // return data if user authenticated by token
}
在上述体系结构中,authToken的作用与ASP .Net表单身份验证中的身份验证cookie相同,但它是作为一个简单参数传递的。您将负责实现生成令牌的算法(必须足够长且唯一,使用类似于此处所述的算法),以及存储和验证它们。

1
在GetAllEmployees中,由于它不维护状态,令牌将如何被访问?传递给GetAllEmployees的authToken将与什么进行检查? - Anil Purswani
1
@Anil,认证令牌可以存储在不同的持久化数据存储中,例如数据库。 - Florin Dumitrescu
为什么不使用头文件来存储和管理服务层状态,而不是使用数据库呢?此外,这会使我们需要定期销毁它的额外开销。客户端可以添加头文件,我们可以在应用程序_AuthenticateRequest事件中验证头文件。头文件可以包含任何内容,如加密的用户名和密码或令牌。 - Anil Purswani
@Anil,头部是在客户端和服务器之间传递数据的一种方式,而不是存储数据的方式。您可以使用头部传递令牌,但是仍然需要在服务器端验证它们,这意味着在其有效期内,它们需要在数据存储中持久化。数据库只是其中的一个选项,您可以选择最适合您的选项。传递加密的用户+密码是一个糟糕的选择,因为:a)它将等同于无限登录会话(除非更改密码,否则无法控制过期),b)您不应该存储密码。 - Florin Dumitrescu
在这种情况下,我们需要在您在服务层提到的登录方法中传递用户名/密码...这又是一个安全威胁...(即使它已经加密)...正如您所提到的,首先调用服务的登录方法,然后发出令牌,然后使用传递给它的令牌调用rest方法...我提到的方法不需要存储在持久化数据存储中...在服务器端,您可以将其保存在配置键中(再次加密),并从配置设置中进行比较...此外,我说您可以传递用户名/密码或加密令牌。 - Anil Purswani

2
WCF Web Api使编写WCF Rest服务变得非常容易,但它有一些限制。对于身份验证,您需要使用WCF Rest Contrib
如果您想要最大程度地控制服务设计,则应退回到ASP.NET MVC,并为每个服务方法编写控制器方法。

1
一种方法是使用安全密钥和令牌。
  1. 每个客户端都有一个安全密钥,在第一次请求时发送,通常在头部。
  2. 您可以生成密钥,例如key = MD5Hash(username+password)。
  3. 响应中会返回一个令牌,然后在每个请求中发送该令牌。令牌可以是Guid。每个令牌在x分钟后过期。
  4. 在服务器端,您可以维护一个单例字典,例如Dictionay,以检查令牌到期时间,当当前时间>到期时间时,请从字典中删除它。
  5. 要更新会话,请在代码中放置更新会话方法。
为了极高的安全性,
客户端将使用公钥加密整个POST数据,您将使用私钥解密。

-1

这是一个使用asp.net mvc完成的示例

当我调用http://localhost:57322/Test/SecureMethod/时,会出现错误。但是如果我先调用http://localhost:57322/Test/Login?username=test&password=abc,然后再调用原始URL,则会返回有效结果。

namespace MvcApplication1.Controllers
{
    public class TestController : Controller
    {
        public ActionResult Login(string username, string password)
        {
            if (username=="test" && password == "abc")
            {
                FormsAuthentication.SetAuthCookie(username, true);
                return Json(true, JsonRequestBehavior.AllowGet);
            }
            return Json(false, JsonRequestBehavior.AllowGet);
        }

        [Authorize]
        public ActionResult SecureMethod()
        {
            return Json("Hello world",JsonRequestBehavior.AllowGet);
        }

    }
}

如果您已经编写了 .svc 文件并且它们不是通过 MVC 完成的,那么您可以将它们放在通过 web.config 安全保护的任何文件夹中,然后在进行任何安全调用之前使用上面的登录方法进行登录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接