Laravel:生成随机唯一令牌
Posted
技术标签:
【中文标题】Laravel:生成随机唯一令牌【英文标题】:Laravel: Generate random unique token 【发布时间】:2016-01-24 21:55:36 【问题描述】:我的数据库中有一个名为 keys
的表,其结构如下:
id | user_id | token_id | token_key
每次用户登录我的网站时,我都需要为该用户生成一个新的token_id
和token_key
集。如何为token_id
和token_key
生成随机令牌,同时保持这两个值的唯一性?
例如,如果:
token_id
是 dfbs98641aretwsg
,
token_key
是 sdf389dxbf1sdz51fga65dfg74asdf
意思:
id | user_id | token_id | token_key
1 | 1 | dfbs98641aretwsg | sdf389dxbf1sdz51fga65dfg74asdf
表中没有其他行具有该标记组合。我该怎么做?
【问题讨论】:
【参考方案1】:在生成令牌方面,您可以使用Laravel's Helper Functions 之一; str_random()
.
这将生成一个指定长度的随机字符串,例如str_random(16)
将生成一个包含 16 个字符(大写、小写和数字)的随机字符串。
根据您使用令牌的方式,它们真的需要完全独一无二吗?鉴于它们将与用户匹配,或者我假设您可能正在使用token_id
,然后根据token_key
验证这一点,如果其中一个是双倍的,这真的很重要吗? - 虽然这种可能性非常小!
但是,如果您确实需要它们真正唯一,您始终可以使用带有unique
约束的验证器。使用this package,您还可以使用unique_with
测试它们两个是否也是唯一的。然后如果验证器失败,它会根据需要生成一个新的令牌。
根据您的示例,您将使用 str_random(16)
代表 token_id
和 str_random(30)
代表 token_key
。
【讨论】:
【参考方案2】:我会避免为这种情况添加额外的包裹。比如:
do
$token_id = makeRandomToken();
$token_key = makeRandomTokenKey();
while (User::where("token_id", "=", $token_id)->where("token_key", "=", $token_key)->first() instanceof User);
...应该可以。如果与“用户”不同,请用您的模型名称替换模型名称,并使用您或建议的函数来创建随机字符串。
【讨论】:
do-while
只要“while”中的语句评估为true
,循环就会继续“执行”(并且它至少会运行一次,与while-do
不同)。在这个特定的示例中,它将生成令牌 ID/密钥对,然后它将尝试在数据库中找到具有该特定令牌和密钥对的用户。 instanceof
检查结果是否是 User
类的实例,这意味着它正在检查是否找到了这样的用户。如果是,do
将再次执行并生成另一对,依此类推,直到它发现没有用户拥有生成的令牌 id/key 对。
这是一个非常糟糕的解决方案!每次要添加新记录时,您都不应该希望遍历数据库表中的每条记录。您最好使用基于时间的唯一字符串。
每次添加新记录时,不是循环遍历表中的每条条记录。请尝试理解do-while
循环。
我同意@Marten。不是一个好的解决方案。它有两点错误:首先,每次创建新令牌时至少要访问数据库一次 - 如果令牌存在于数据库中,则再次访问它。其次,不能保证唯一性。在您检查其是否存在之后以及在将其插入当前线程之前,另一个线程可以将相同的密钥插入到数据库中。为什么不使用在唯一性方面具有高度安全性的 UUID?
一种可能的改进是尝试插入新标记而不是选择它们。如果它们不是唯一的,请求将失败(假设数据库正确设置了唯一索引),然后您返回循环并创建一个新对并重试,直到操作成功。这将保证操作的原子性。【参考方案3】:
您可以使用依赖项来执行此操作。 Dirape laravel-token
运行命令
composer require dirape/token
在你的控制器中使用
use Dirape\Token\Token;
你可以这样使用它:
User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'token_key' => (new Token())->Unique('users', 'api_token', 60),
'active' => 1
])
【讨论】:
【参考方案4】:遵循@ivanhoe 的建议...这是我想出的:-
$token = new Token;
//in case there are duplicate
for ($x = 0; $x < 10; $x ++)
$token->access_token = str_random(16);;
try
if ($token->save())
break;
catch (QueryException $e)
【讨论】:
以上是关于Laravel:生成随机唯一令牌的主要内容,如果未能解决你的问题,请参考以下文章
如何在laravel中为每个用户生成唯一的随机值并将其添加到数据库中
如何在 laravel 中为每个用户生成唯一的自动增量值并将其添加到数据库中