PostgreSQL: Create Access Token on Insert
在插入时,如何将EDOCX1的值(0)唯一地设置为随机字符串并将该值返回给客户机?
我有:
1 2 3 4 5
| 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
- 为什么这是一个鲁比问题?
- 你考虑过触发因素吗?当发生插入时,可以定义触发器,以便将access_token设置为随机字符串,并返回该值?请参见postgresql.org/docs/9.3/static/sql-createligger.html
- @因为我不确定解决方案堆栈的哪个部分应该这样做。
- 相关问题,除了不需要唯一性:dba.stackexchange.com/questions/19632/…
- 在列上使用UUID和默认值怎么样?postgresql.org/docs/current/static/datatype-uuid.html文件
- @用户102890感谢您通知我有关触发器的信息。不过,我认为,根据a_horse_with_no_name的建议,列上的默认值似乎是一个更简单的解决方案。
在阅读了RubyonRails安全指南并研究了其他成功的应用程序是如何做到这一点之后,我找到了一种生成访问令牌的更好方法。
旧思维
在问这个问题之前,我已经使用了Facebook图形API,我知道我希望能够提出一个安静的请求,比如:
1
| GET /me?access_token=4976517fd7814040b2083864973ff422 |
从access_token服务器可以返回关于me的信息。
因此,我认为access_token必须是UNIQUE,这样服务器才能执行如下操作:
1
| SELECT * FROM users WHERE access_token = '4976517fd7814040b2083864973ff422' |
新思维
让我们看看其他成功的API中访问令牌的一些例子。
facebook:50601675619|5Lfrygz7QmiNVSgkvryzixIVHuo(app token)推特:191074378-1GWuHmFyyKQUKWV6sR6EEzSCdLGnhqyZFBqLagHp实例图:fb2e77d.47a0479900504cb3ab4a1f626d174d2d。Github:e72e16c7e42f292c6912e7710c838347ae178b4a。
Facebook和Twitter都清楚地在用户的访问令牌前面加上了自己的ID。Instagram似乎也这样做,只是进行了编码。这样的访问令牌基本上有两部分:用户ID和会话ID。
嵌入用户ID的访问令牌允许服务器:
1
| SELECT * FROM users WHERE id = '50601675619' |
然后,它可以简单地检查访问令牌的第二部分是否与存储在该用户数据库中的会话ID匹配,类似于在登录期间验证用户名和密码。
最终解决方案
Instagram访问令牌的第二部分似乎是无连字符的较低版本4 UUID。因此,我将按照@a_horse_的评论和@clodoaldoneto的回答来做同样的事情。但是,我将把列access_token重命名为session_id并删除UNIQUE约束。
如上所述,使用uuid型
1 2 3 4 5
| 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
); |
然后插入默认值
1 2 3 4 5
| INSERT INTO user_table DEFAULT VALUES
returning access_token;
access_token
--------------------------------------
341ab75c-6b4e-4df0-a2ea-5148434fce5a |
为了能够使用uuid功能,需要在目标数据库中安装uuid-ossp扩展作为超级用户。
1
| CREATE extension"uuid-ossp"; |
您可以使用Ruby中的uuid函数,或者如果它们不存在于其他地方。
现在阅读您的评论,看起来您正在处理会话ID。
可以使用UUID生成器生成会话ID。但请注意,会话ID只是特定会话的ID。每次用户登录时,它都会更改。会话ID不应存储在用户表中。
通常,会话由应用程序使用框架提供的模块处理。该模块将有自己的方法来存储会话ID和会话数据。一般来说,会话ID放在cookie中,而不是URL中。应用程序将向会话管理器传递一个salt,它将负责生成会话ID并保持其状态,无论是在cookie中、在URL中、在页面中,无论是什么。模块将把会话数据存储在它配置的位置,内存、磁盘文件、数据库。
所以不要自己做会话管理。让它进入框架的解决方案。更简单,更重要,更安全。
- 谢谢!如何保证生成的UUID在所有用户的访问令牌中都是唯一的?我不想处理可能插入重复的access_token所导致的错误。我不喜欢这个错误的一个原因是它增加了serial,即使没有插入任何内容,也会导致id中的间隙。
- @mattdipasquale:序列A生成的ID完全没有意义,因此序列中的间隙也没有意义。UUID对于您的用例来说应该足够独特——特别是如果只在单个系统上创建的话。
- @一匹没有名字的马,我相信没有什么是无意义的,任何事都是可能的。但是无论如何,我发现了一个更好的实现,它不需要UUID是唯一的。谢谢你的帮助!-)
- @matddipasquale:一个序列中的井隙是没有意义的。如果你关心它们,那么你就误解了它们的作用:产生唯一的数字——那,而且只是那。
- @一匹没有名字的马,有一点我不喜欢间隙,那就是如果你不小心的话,它们可以显著减少你可以在表中插入的行数。例如,如果您使用smallserial(最大32767),但有10000个插入错误,因为一些白痴一直试图注册已经使用过的用户名,那么您只能在表中插入22767个用户,而不是32767个。
- @一匹没有名字的马,我希望用户ID像在Facebook上那样,意味着该用户是(至少是)第n个要加入的用户。我记得当facebook流行的时候,我和我的朋友们会比较用户ID来吹嘘谁先加入。:-)我觉得很酷。
- @matddipasquale:如果您关心插入的数量,那么为什么首先使用smallserial?使用bigserial,你永远不会用完数字。将自己限制在32767行是值得怀疑的。
- @一匹没有名字的骏马,我觉得serial比big serial更有效(更小,更快),而且如果应用程序比Facebook现在更受欢迎的话,我可以一直使用ALTERinteger到bigint。
- @matddipasquale:如果您只期望32768个用户,那么使用smallint、int或bigint不会有任何不同。
- @一匹没有名字的骏马,也许我想要的用户ID也意味着你要加入这个应用程序的用户数量,这意味着我应该使用除serial以外的东西。我是PostgreSQL的新手,也是SQL的新手。所以,我可能做得不对。
- @一匹没有名字的马,我什么也不想。我不怕任何人。我自由了。"—尼科斯·卡赞扎基斯
- 不过,你说得不错。也许你说服我用big serial而不是serial。
- @matddipasquale a uuid是一个16字节的数字。大到可以被认为是独一无二的。即使有数以百万计的用户,发生冲突的可能性也很小。检查我的更新答案
- @感谢您提供最新的答案。这帮了很多忙。但是,我还需要将用户连接到node.js websocket chat server,该服务器与restful sinatra服务器分开。所以,我想我需要一个OAuth2访问令牌。也许我会做一张叫clients的桌子,把client_id和client_secret放在里面。iPhone应用程序可以是一个客户端,Web应用程序可以是另一个客户端。我想我可以把用户的访问令牌存储在redis中。或者,也许我应该使用现有的OAuth2授权服务器。