【问题标题】:RESTful API database authentication, which verb?RESTful API 数据库认证,哪个动词?
【发布时间】:2016-05-25 10:23:17
【问题描述】:

我需要一个 API 调用来验证登录。我们有一个带有用户表的数据库,我们正在构建一个前端,中间有一个 API。前端从用户那里获取用户名和密码,我们需要使用 API 针对数据库对这些凭据进行身份验证。

所以我们有:

  1. 请求对用户进行身份验证
  2. 表明是否通过身份验证的响应

请求

我猜请求应该是GET,因为POST 用于创建,PUT 用于更新,而我们都没有这样做。

我们需要将用户名和密码发送到服务器,并且由于我们使用的是GET,我是否正确地说我们只能使用查询字符串参数或标头来发送数据..?

我认为查询字符串参数不适合密码等,因此会为请求留下标题:

GET https://my-local-api-server/authenticate HTTP/1.1
username: my.username
password: mypassword

这是一个正确的 RESTful 请求,将数据发送到服务器进行身份验证..?

响应

对于响应,我们应该只使用响应状态码(200 或 401),还是应该发送包含身份验证请求结果的 JSON..?

{
    "authenticated": true,
    "error": ""
}

{
    "authenticated": false,
    "error": "Some error message..."
}

哪个是正确的 RESTful 响应..?还是两者兼而有之?

更新

我的问题不是很好,所以我需要澄清一下。

我不应该在上面的示例中使用公共 URL,这实际上是一个本地服务器和本地 API,它永远不会被外部使用,只会被其他本地应用程序内部使用。如果这种情况发生变化,我们可以重新审视我们正在做的事情。

我想我不清楚我正在做的身份验证,这让我有些困惑。我正在根据数据库对用户(现实世界的人)进行身份验证。我没有验证 API 的使用。

我们要编写的应用程序都是内部应用程序,无需进行身份验证即可使用 API。没有 API 密钥等。

所以...我正在寻找一个真实世界的人,并检查他们是否应该可以访问我们的应用程序,而不是检查我们的应用程序是否可以访问 API。

【问题讨论】:

    标签: api rest authentication


    【解决方案1】:

    REST 中的身份验证概述

    在 REST API 中,当访问需要身份验证的受保护资源时,每个请求都必须包含所有必要的数据才能正确地进行身份验证/授权。并且身份验证数据(凭据)应该属于标准的 HTTP Authorization 标头:

    4.2. Authorization

    Authorization 标头字段允许用户代理进行身份验证 本身与原始服务器 - 通常,但不一定,之后 收到401(未经授权)响应。它的价值包括 包含用户身份验证信息的凭据 被请求资源领域的代理。

    Authorization = credentials
    

    [...]

    请注意,此 HTTP 标头的名称是 unfortunate,因为它携带 authentication 数据而不是 authorization。无论如何,这是在 HTTP 协议中发送 凭据 的标准标头。

    REST 应用程序应该是无状态的,因此服务器端不能存储会话状态。相反,会话状态必须完全由客户端处理,正如 Roy T. Fielding 的 dissertation about REST 中所定义的那样:

    5.1.3 Stateless

    [...] 从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。 [...]

    因此,您使用的动词无关紧要,如果您正在对受保护资源执行请求,则该请求应包含身份验证数据。

    基本认证

    保护 REST API 的常用方法是使用 Basic Authentication Scheme

    2. The 'Basic' Authentication Scheme

    基本身份验证方案基于客户端的模型 需要使用每个用户的用户 ID 和密码进行身份验证 保护空间(“领域”)。 [...]服务器只有在可以验证的情况下才会为请求提供服务 申请的保护空间的用户名和密码 请求的资源。

    [...]

    为了获得授权,客户端

    1. 从用户那里获取用户ID和密码,

    2. 通过连接 user-id 来构造用户通行证,单个 冒号 (":") 字符和密码,

    3. 将用户密码编码为八位字节序列,

    4. 并通过编码此八位字节序列获得基本凭证 使用Base64US-ASCII characters 的序列中。

    [...]

    如果用户代理希望发送用户 ID“Aladdin”和密码 “芝麻开门”,它将使用以下头字段:

    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    

    [...]

    基于令牌的身份验证

    正在发生的另一种方法是基于令牌的身份验证。在这种方法中,您基本上将硬凭证(用户名和密码)交换为客户端必须在每个请求中发送的令牌。在这种方法中,您可以使用POST 执行身份验证,在请求负载中发送凭据:

    POST /api/authentication HTTP/1.1
    Host: example.com
    Content-Type: application/json
    
    {
        "username": "username",
        "password": "password"
    }
    

    如果身份验证成功,则在响应负载中返回 200 状态码和令牌:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
        "authenticationToken": "<token goes here>"
    }
    

    否则,如果凭据无效,则返回401

    请务必注意,令牌是将用于验证后续请求的凭据。因此,令牌也应该在 Authorization 标头中发送:

    Authorization: Bearer <token goes here>
    

    【讨论】:

    • 虽然这可行,但我们没有创建任何东西,所以我不相信使用POST
    • POST 是一个 catch all 动词,也适用于身份验证。
    • @StephenLast 在 REST API 中,对保护资源的每个请求都必须包含身份验证。例如,我在回答中提到的方法适用于您为令牌交换硬凭证(用户名和密码)的情况。
    • 非常感谢您提供的所有这些信息,它非常有用。我已经为我的问题添加了更新。考虑到更新,您认为我应该使用基于令牌的身份验证(POST with JSON)吗?
    • @StephenLast 基本身份验证方案非常适合您想要实现的目标。
    【解决方案2】:

    通过 HTTP 向 API 发送用户名和密码的最标准方法是使用 Basic Auth 标头。

    对于响应,您绝对应该使用正确的 HTTP 状态代码(例如 Forbidden),但您仍然可以在正文中包含带有更多信息的 JSON 有效负载。

    【讨论】:

    • 发送基本身份验证标头时应该使用什么动词..?到目前为止的另一个答案(来自 Cássio Mazzochi Molin)建议使用 POST 而不是 GET
    • 认证调用的结果是什么?你得到一个新铸造的会话令牌吗?如果是这样,POST 听起来更好。如果只是检查密码是否正确,那么GET。但这本身有什么用呢? OTOH,如果您只是向每个 API 调用发送凭据,则根本不需要单独的请求。
    • 目前,只需要一次调用即可对某人进行身份验证,没有创建会话。如果我们确实创建了一个会话,那么是的,我知道POST 是有道理的。
    猜你喜欢
    • 2011-04-01
    • 2015-11-05
    • 2018-12-19
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 2019-08-31
    • 2016-12-16
    • 1970-01-01
    相关资源
    最近更新 更多