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

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

id | user_id | token_id | token_key

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

例如,如果:

  • token_iddfbs98641aretwsg
  • token_keysdf389dxbf1sdz51fga65dfg74asdf

意思:

id | user_id | token_id         | token_key
1  | 1       | dfbs98641aretwsg | sdf389dxbf1sdz51fga65dfg74asdf

表中没有其他行具有该标记组合。我该怎么做?

【问题讨论】:

    标签: php laravel laravel-4 laravel-5


    【解决方案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) {
        
                }
            }
        

        【讨论】:

          猜你喜欢
          • 2014-04-16
          • 2020-09-20
          • 2020-05-27
          • 2019-01-12
          • 2011-08-19
          • 2012-12-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多