Laravel:生成随机唯一令牌

Posted

技术标签:

【中文标题】Laravel:生成随机唯一令牌【英文标题】:Laravel: Generate random unique token 【发布时间】:2016-01-24 21:55:36 【问题描述】:

我的数据库中有一个名为 keys 的表,其结构如下:

id | user_id | token_id | token_key

每次用户登录我的网站时,我都需要为该用户生成一个新的token_idtoken_key 集。如何为token_idtoken_key 生成随机令牌,同时保持这两个值的唯一性?

例如,如果:

token_iddfbs98641aretwsgtoken_keysdf389dxbf1sdz51fga65dfg74asdf

意思:

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_idstr_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 护照令牌

如何在 laravel 中为每个用户生成唯一的自动增量值并将其添加到数据库中

Laravel 护照授权令牌在生成新令牌时过期

Laravel 手动生成重置密码令牌:收到错误“此密码重置令牌无效”

Laravel 从登录中获取生成的刷新令牌