0

目标

我有一张一次性使用令牌表;最多一个线程应该能够读取任何给定的行。如果竞争条件导致一行根本不可读的可能性很小,这是可以接受的。

为什么

我正在 OAuth2 中实现授权代码流。服务器创建一个具有唯一 ID 的“授权码”授权令牌,并将其交给客户端;客户很快回来并尝试将身份验证代码兑换为真正的访问令牌。这种赎回最多只能发生一次;如果攻击者获得了授权码,但客户端首先赎回了它,那么攻击者也一定无法赎回它。

身份验证码最多在 10 分钟后过期;我存储了一个过期时间戳列来检查赎回,但我也使用 Cassandra 的 TTL 功能(列过期)进行垃圾收集。

这里的所有操作都使用 LOCAL_QUORUM 执行。每个授权码由一行表示,其键等于授权码值。

不满意/损坏的解决方案

  • 计数器列
    • 维护一个用于验证代码兑换的计数器列。当一个线程试图赎回一个授权码时,它首先在计数器列中增加授权码的行,然后读取授权码的列。如果计数大于 1,则拒绝。在竞争条件下,两个线程都可能拒绝。
    • 有效性:我相信只有全失败错误才会正确运行。
    • 缺点:Cassandra不支持计数器列的 TTL,这意味着我必须运行一个 reaper 进程。
  • 迪布斯
    • 维护一个名为“dibs”的字符串列。当一个线程试图赎回一个授权码时,它会将一个唯一的 ID 写入 dibs 列,然后读取这些列。如果 dibs 值不再匹配,则拒绝。
    • 有效性:没有。线程 1 写入、读取、接受。线程 2 写入、读取、接受。这不能通过仅在读取后添加删除或第二次写入来解决,因为这可能发生在其他线程的操作之后。

可能的解决方案

Lamport 的面包店算法看起来非常合适,但可能是矫枉过正。

问题

我是否坚持使用协作单读者锁定的计数器列?

4

1 回答 1

1

这不是您问题的直接答案,但希望是有用的信息。

Cassandra 2.0 将支持 compare-and-swap - 你的“dibs”方法的服务器端实现,应该确保一致性。从发行说明中可以看出,Cassandra 2.0 的 thrift 和 2.0.1 的 CQL 都支持此功能。

根据您的时间范围和可能使用 x.0 版本的意愿,这可能是一个解决方案。

于 2013-07-29T23:05:48.187 回答