传统 Web 应用程序和 API 中的认证、授权和会话管理

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

但是,在一个基于 API 的应用程序中,这些信息不会自动发送,所以在开发一个 API 时,我必须检查自己这个请求是否来自一个经过身份验证的用户,例如?这通常是怎么做的?

75673 次浏览

会话管理由服务器负责。创建会话时,会生成一个会话标记并将其发送到客户端(并存储在 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;
}

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

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

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

饼干

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

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

面向 Web 的编程语言/框架提供了在更高层次上处理 Cookie 的函数,例如,PHP 提供了 setcookie/$_COOKIE来写/读 Cookie。

会议

回到会话,在典型的浏览器-服务器情况下,服务器端会话管理利用客户端 Cookie 管理。PHP 的会话管理设置一个会话 ID cookie 并使用它来标识后续请求。

Web 应用程序 API? ?

现在回到您的问题; 因为您将负责设计 API 并编写文档,所以实现将由您决定。基本上你必须这么做

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

当然,您可以在现有的基础设施上进行构建,您可以使用 PHP 的会话管理(它将处理1。/2.以及4的认证部分。)并要求客户端实现执行 Cookie 管理(这将处理3)然后在那上面完成剩下的应用程序逻辑。


(*)每种方法都有优缺点,例如,使用 GET 请求参数更容易实现,但是可能会有安全隐患,因为 GET 请求会被记录下来。您应该使用 https 来处理关键(全部?)申请。

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

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

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

另一件需要考虑的事情是您将在 API 中对服务器上的会话执行什么操作。网站上的会话为当前用户提供存储,并且通常存储少量数据,以便从一个页面到另一个页面减轻数据库的负载。在 API 上下文中,由于事物或多或少都是无状态的,所以不需要这样做,当然,一般来说,这确实取决于服务正在做什么。

我建议你每次提出要求时,都要附上一些信物。

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

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

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

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

提供用户名/密码对不仅是身份验证的方法,如果使用 HTTPS 协议,还可以考虑 使用数码证书身份验证。

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

综上所述,我认为对以下问题的回答进入了选择 WebApi 授权/认证机制的决策过程:

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

还有更多。

希望这样能把事情搞清楚一点,因为方程式中有很多变数。