用户 API 密钥:重复的 client_id 会导致内部服务器错误

当使用已被其他用户使用的 client_id 调用 user-api-key/new 时,论坛将抛出 RecordNotUnique 错误,并在内部服务器错误中静默失败。

ActiveRecord::RecordNotUnique (PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_user_api_keys_on_client_id"
DETAIL:  Key (client_id)=(893e0230d52455ea9b729334) already exists.
)
(eval):105:in `exec_params'
app/controllers/user_api_keys_controller.rb:66:in `create'

这可能需要以一种不那么静默的方式失败,告知用户已存在具有该客户端 ID 的 API 密钥。

不过,这引出了第二个问题,用户 API 密钥应该这样运行吗?客户端 ID 应该在所有用户之间是唯一的吗?

5 个赞

快速提醒以提高可见性。我们仍然在 /logs 端点中相当频繁地看到这些错误:

image

3 个赞

感谢您报告此问题,但我有几个问题需要进一步了解才能帮助您解决。\n\n[quote="Indra, post:1, topic:260995"]\n调用 user-api-key/new 时,client_id 已被另一用户使用\n[/quote]\n\n您能否提供一个基本的重现步骤,以便我在本地调试?您的 user-api-keys 的使用场景是什么?您使用的是 discourse hub 移动应用程序还是其他什么?

1 个赞

我不确定你偏好哪种复现方式,但这段 PHP 代码可以很好地复现它。

代码

// openssl genrsa -out keypair.pem 2048
$keypair = openssl_pkey_get_private(file_get_contents("keypair.pem"));

// 获取公钥
$public = openssl_pkey_get_details($keypair)["key"];

// 构建查询
$query = http_build_query([
    "auth_redirect" => "https://localhost/redirect",
    "application_name" => "Test repro",
    "client_id" => "7624a5376b7f52eb403a",
    "scopes" => "session_info",
    "nonce" => bin2hex(random_bytes(16)),
    "public_key" => $public
]);

$url = "https://forum.cfx.re/user-api-key/new?" . $query;
header("Location: " . $url);

第一次授权并重复授权会成功,作为第一个用户。当不更改 client_id 而再次使用它为另一个用户时,将会失败。
image

用户 API 密钥用于允许用户在游戏客户端中使用他们的论坛账户,这样他们就可以从游戏内发帖。我们也有很多用户使用它们来验证他们自己的网站上的论坛账户。

而 client ID 对于游戏客户端应该是唯一的,所以每个客户端在应用程序屏幕上都会被列为一个单独的客户端。对于网站用例,你希望有一个 client ID,这样就不会为每次登录单独列出。

3 个赞

不知道这个问题是否已解决

关于此问题是否有任何更新?目前尚不清楚 client_id 是否应全局唯一而不是每个用户唯一。

1 个赞

它应该是全局唯一的。

应该如何为没有自己的用户身份验证系统且不应创建多个用户 API 应用程序的网站用例实现这一点?

2 个赞

设置 Cookie?或者通过哈希一个标识用户的标识符(加上一些“秘密”信息,以防止外部方复制)来确定它

如果需要跨多台计算机使用的应用程序在身份验证用户之前没有任何用户数据,那么这是不可能的。

我不明白这与 OP 有何关联,因为 OP 描述的是一个客户端 ID 由多个用户共享的情况,而您的情况似乎描述的是一个用户拥有多个客户端 ID 的情况。

它被称为客户端 ID 而不是用户 ID,因为一个用户可以拥有多个客户端!

在大多数标准(如 OAuth)中,客户端 ID 被描述为“应用程序标识符”,可供所有用户使用(而不仅仅是一个用户)。例如,您的论坛社交登录始终使用相同的客户端 ID。

然而,由于用户 API 密钥似乎主要为 Discourse 应用等客户端设计,因此它们可能被设计为唯一的。我们很想知道它们是否确实是唯一的。

回答上述问题将清楚地表明 user_api_keys.rb 中是否缺少检查,或者数据库中是否存在错误的索引。因为目前这些请求会引发可怕的 500 错误,并显示在我们的 /logs 端点中。

1 个赞

对此有任何更新吗?我们仍然看到用户遇到此问题。

1 个赞

错误应该更好,是的,但 client_id 需要是唯一的。

当您以这种方式发送用户时,您必须在 API 调用中生成一个唯一的 id。索引是正确的,1 个用户可以有 N 个 client id。