【问题标题】:PostgreSQL: Create Access Token on InsertPostgreSQL:在插入时创建访问令牌
【发布时间】:2014-03-07 23:17:19
【问题描述】:

在插入时,我应该如何将uniquely set 的值access_token 转换为random string 并将该值返回给客户端?

我有:

CREATE TABLE user (
    id             serial PRIMARY KEY,
    access_token   char(32) NOT NULL UNIQUE,
    joined         timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP
);

数据库服务器:PostgreSQL
应用服务器:Sinatra (Ruby)
客户端:iOS

【问题讨论】:

标签: postgresql stored-procedures access-token


【解决方案1】:

在阅读了Ruby on Rails Security Guide 和studying how other successful apps do it 之后,我想出了一个更好的生成访问令牌的方法。

旧思维

在问这个问题之前,我玩过Facebook Graph API,我知道我希望能够提出一个 RESTful 请求,例如:

GET /me?access_token=4976517fd7814040b2083864973ff422

从access_token,服务器将能够返回有关me的信息。

因此,我认为 access_token 必须是 UNIQUE 以便服务器可以执行以下操作:

SELECT * FROM users WHERE access_token = '4976517fd7814040b2083864973ff422'

新思维

让我们看一些来自其他成功 API 的访问令牌示例。

Facebook:50601675619|5Lfrygz7QmiNVSgkvryzixIVHuo(应用令牌)
Twitter:191074378-1GWuHmFyyKQUKWV6sR6EEzSCdLGnhqyZFBqLagHp
Instagram:fb2e77d.47a0479900504cb3ab4a1f626d174d2d
GitHub:e72e16c7e42f292c6912e7710c838347ae178b4a

Facebook 和 Twitter 都清楚地在用户的访问令牌前加上他的 ID。 Instagram 似乎也在做同样的事情,只是进行了编码。这样的访问令牌本质上包含两部分:用户 ID 和会话 ID。

嵌入了用户 ID 的访问令牌允许服务器:

SELECT * FROM users WHERE id = '50601675619'

然后,它可以简单地检查访问令牌的第二部分是否与该用户存储在数据库中的会话 ID 匹配,类似于在登录期间验证用户名和密码。

最终解决方案

Instagram 访问令牌的第二部分似乎是不带连字符的小写 version 4 UUID。所以,我会按照comment by @a_horse_with_no_name 和answer by @ClodoaldoNeto 来做同样的事情。除了,我会将列 access_token 重命名为 session_id 并删除 UNIQUE 约束。

【讨论】:

    【解决方案2】:

    如上所述,使用uuid 类型

    create table user_table (
        id             serial primary key,
        access_token   uuid default uuid_generate_v4() not null unique,
        joined         timestamp with time zone not null default current_timestamp
    );
    

    然后插入默认值

    insert into user_table default values
    returning access_token;
                 access_token             
    --------------------------------------
     341ab75c-6b4e-4df0-a2ea-5148434fce5a
    

    为了能够使用uuid 功能,需要在目标数据库中以超级用户身份安装uuid-ossp 扩展

    create extension "uuid-ossp";
    

    您可以使用 Ruby 中的 uuid 函数,或者如果它们在其他地方不存在。


    现在正在读取您的 cmets,看起来您正在使用会话 ID。

    可以使用 UUID 生成器生成会话 ID。但请注意,会话 ID 只是某个会话的 ID。每次用户登录时它都会改变。会话ID不应该存储在用户的表中。

    一般来说,会话​​是由应用程序使用一些框架提供的模块来处理的。该模块将有自己的方式来存储会话 ID 和会话数据。通常,会话 ID 位于 cookie 中,而不是 URL。应用程序将向会话管理器传递一个盐,它会负责生成会话 ID 并保持其状态,无论是在 cookie、URL 还是页面中,等等。该模块会将会话数据存储在它配置的位置,内存,磁盘文件,数据库。

    所以不要自己进行会话管理。让它成为框架的解决方案。简单得多,非常重要,也更安全。

    【讨论】:

    • 谢谢!如何保证生成的 UUID 在所有用户的访问令牌中是唯一的?我不想处理由可能插入重复的access_token 引起的错误。我不喜欢这个错误的一个原因是,即使没有插入任何内容,它也会增加serial,从而导致id 出现间隙。
    • @MattDiPasquale:序列生成的 id 完全毫无意义,因此序列中的间隙也是无意义的。 UUID 对于您的用例应该足够独特 - 特别是如果仅在单个系统上创建。
    • @a_horse_with_no_name 我相信nothing is meaningless,一切皆有可能。但无论如何,我想出了一个更好的实现,它不需要 UUID 是唯一的。谢谢您的帮助! :-)
    • @MattDiPasquale:序列中的井间隙毫无意义。如果您担心它们,那么您误解了它们的作用:生成唯一编号 - 仅此而已。
    • @MattDiPasquale:如果您希望只有 32768 个用户,那么使用 smallint、int 或 bigint 不会有任何区别。
    猜你喜欢
    • 1970-01-01
    • 2015-04-12
    • 2011-10-22
    • 2019-03-27
    • 1970-01-01
    • 2013-09-03
    • 2018-06-02
    • 2021-10-18
    • 1970-01-01
    相关资源
    最近更新 更多