75

如果我错了,请纠正我:在传统的 Web 应用程序中,浏览器会自动将会话信息附加到对服务器的请求中,因此服务器可以知道请求来自谁。实际上到底附加了什么?

但是,在基于 API 的应用程序中,这些信息不会自动发送,因此在开发 API 时,我必须检查自己是否请求来自经过身份验证的用户?这通常是如何完成的?

4

6 回答 6

124

HTTP 协议在设计上是无状态的,每个请求都是单独完成的,并在单独的上下文中执行。

会话管理背后的想法是将来自同一客户端的请求放在同一上下文中。这是通过服务器发出一个标识符并将其发送给客户端来完成的,然后客户端将保存此标识符并在后续请求中重新发送它,以便服务器可以识别它。

饼干

在典型的浏览器服务器案例中;浏览器为每个域管理一个键/值对列表,称为 cookie:

  • Cookie 可以由服务器使用Set-CookieHTTP 响应标头管理(创建/修改/删除)。
  • 服务器可以通过解析CookieHTTP 请求头来访问(读取)Cookie。

面向 Web 的编程语言/框架提供了处理更高级别 cookie 的函数,例如 PHP 提供setcookie/$_COOKIE来写入/读取 cookie。

会话

回到会话,在典型的浏览器服务器案例中(再次),服务器端会话管理利用客户端 cookie 管理。PHP 的会话管理设置一个会话 id cookie 并使用它来识别后续请求。

网络应用程序 API?

现在回到你的问题;由于您将负责设计 API 并对其进行记录,因此实施将由您决定。你基本上必须

  1. Set-Cookie在响应正文(XML/JSON auth 响应)中为客户端提供一个标识符,无论是通过HTTP 响应标头。
  2. 具有维护标识符/客户端关联的机制。例如,将标识符00112233445566778899aabbccddeeff与客户端/用户 #相关联的数据库表1337
  3. 让客户端在所有后续请求中重新发送在 (1.) 处发送给它的标识符,无论是在 HTTPCookie请求标头中,?sid=00112233445566778899aabbccddeeff参数 (*)。
  4. 使用 (2.) 中的机制查找接收到的标识符,检查是否是有效的身份验证,并被授权执行请求的操作,然后代表经过身份验证的用户继续操作。

当然,您可以在现有基础架构上构建,您可以在应用程序中使用 PHP 的会话管理(负责 1./2. 和 4. 的身份验证部分),并要求客户端实现进行 cookie 管理(即将处理 3.),然后您在此基础上执行其余的应用程序逻辑。


(*) 每种方法都有优缺点,例如,使用 GET 请求参数更容易实现,但可能具有安全隐患,因为记录了 GET 请求。您应该将 https 用于关键(全部?)应用程序。

于 2012-06-27T23:48:26.960 回答
48

会话管理是服务器的责任。创建会话时,会生成会话令牌并将其发送到客户端(并存储在 cookie 中)。之后,在客户端和服务器之间的下一个请求中,客户端(通常)将令牌作为 HTTP cookie 发送。所有会话数据都存储在服务器上,客户端只存储令牌。例如,要在 PHP 中启动会话,您只需:

session_start();  // Will create a cookie named PHPSESSID with the session token

创建会话后,您可以在其上保存数据。例如,如果您想让用户保持登录状态:

// If username and password match, you can just save the user id on the session
$_SESSION['userID'] = 123;

现在您可以检查用户是否经过身份验证:

if ($_SESSION['userID'])
    echo 'user is authenticated';
else
    echo 'user isn't authenticated';       

如果需要,您可以仅为经过身份验证的用户创建会话:

if (verifyAccountInformation($user,$pass)){ // Check user credentials
    // Will create a cookie named PHPSESSID with the session token
    session_start();
    $_SESSION['userID'] = 123;
}
于 2012-06-23T18:54:31.407 回答
10

对于 Web 应用程序和 API,真实用户有多种方式。有几个标准,或者您可以编写自己的自定义授权/和/或身份验证。我想指出授权和身份验证之间的区别。首先,应用程序需要验证请求来自的用户(或 api 客户端)。一旦用户通过身份验证,应用程序需要根据用户的身份确定任何经过身份验证的用户有权执行某些应用程序(授权)。对于大多数传统的 Web 应用程序,安全模型没有细粒度,因此一旦用户通过身份验证,在大多数情况下,它也被授权执行某些操作。但是,这两个概念(认证和授权)应该是两个不同的逻辑操作。

此外,在经典的 Web 应用程序中,在用户通过身份验证和授权后(主要通过在数据库中查找用户名/密码对),授权和身份信息被写入会话存储中。会话存储不一定是服务器端,正如上面的大多数答案所暗示的那样,它也可以存储在客户端的 cookie 中,在大多数情况下是加密的。例如,PHP CodeIgniter 框架默认执行此操作。在客户端有许多保护会话的机制,我认为这种存储会话数据的方式比存储 sessionId 更安全,然后在服务器端的会话存储中查找。此外,在分布式环境中存储会话客户端非常方便,

此外,使用简单的用户密码对进行身份验证不必在所有情况下都通过自定义代码来完成,该代码在数据库中查找匹配的用户记录。例如,基本身份验证协议摘要身份验证。在Windows平台等专有软件上,也有用户槽认证的方法,例如ActiveDirectory

提供用户名/密码对不仅是认证方式,如果使用 HTTPS 协议,还可以考虑使用数字证书进行认证

在特定的用例中,如果设计使用 SOAP 作为协议的 Web 服务,还有SOAP 协议的WS-Security扩展。

综上所述,我想说以下问题的答案进入了选择 WebApi 授权/身份验证机制的决策程序:

1) 目标受众是什么,是公开的,还是仅限注册(付费)会员?
2) 它是运行还是 *NIX 或 MS 平台
3) 预计有多少用户
4) API 处理多少敏感数据(更强与更弱的身份验证机制)
5) 是否有任何 SSO 服务可供您使用

.. 还有很多。

希望这可以清除一些东西,因为方程中有很多变量。

于 2012-06-29T17:52:49.630 回答
1

我建议您在每个请求中发送某种令牌。

取决于服务器和服务,它们可以是GET/POST 请求中的JSESSIONID参数,也可以是Web 服务请求中 SOAP over HTTP 中的SAML等成熟的参数。

于 2012-06-29T11:54:27.467 回答
1

你是对的,在标准环境中事情是“自动的”的原因是因为 cookie 比 URL 传播更受欢迎,以保持对用户的美观。也就是说,浏览器(客户端软件)管理存储和发送会话 cookie 以及每个请求。

在 API 世界中,简单的系统通常只是将身份验证凭据与每个请求一起传递(至少在我的工作中)。客户端作者通常(再次根据我的经验)不愿意实现 cookie 存储,以及每个请求的传输,并且通常超过最低限度的任何内容......

对于基于 HTTP 的 API,还有很多其他的身份验证机制,例如 HTTP 基本/摘要,当然还有无处不在的 o-auth,如果我没记错的话,它是专门为这些事情设计的。不维护任何 cookie,凭据是每次交换的一部分(相当肯定)。

要考虑的另一件事是您将在 API 中使用服务器上的会话做什么。网站上的会话为当前用户提供存储,并且通常存储少量数据以从页面到页面减轻数据库的负载。在 API 上下文中,这不是必需的,因为事物或多或少是无状态的,当然一般来说;这真的取决于服务在做什么。

于 2012-06-28T18:35:43.427 回答
1

如果基于 API 的 APP 是客户端,则 API 必须具有从服务器响应流中检索/读取 cookie 并将其存储的选项。用于在为同一服务器/url 准备请求对象时自动附加 cookie。如果它不可用,则无法检索会话 ID。

于 2012-06-27T09:45:03.043 回答