DatabaseTokenRepository.php 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. <?php
  2. namespace Illuminate\Auth\Passwords;
  3. use Illuminate\Support\Str;
  4. use Illuminate\Support\Carbon;
  5. use Illuminate\Database\ConnectionInterface;
  6. use Illuminate\Contracts\Hashing\Hasher as HasherContract;
  7. use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
  8. class DatabaseTokenRepository implements TokenRepositoryInterface
  9. {
  10. /**
  11. * The database connection instance.
  12. *
  13. * @var \Illuminate\Database\ConnectionInterface
  14. */
  15. protected $connection;
  16. /**
  17. * The Hasher implementation.
  18. *
  19. * @var \Illuminate\Contracts\Hashing\Hasher
  20. */
  21. protected $hasher;
  22. /**
  23. * The token database table.
  24. *
  25. * @var string
  26. */
  27. protected $table;
  28. /**
  29. * The hashing key.
  30. *
  31. * @var string
  32. */
  33. protected $hashKey;
  34. /**
  35. * The number of seconds a token should last.
  36. *
  37. * @var int
  38. */
  39. protected $expires;
  40. /**
  41. * Create a new token repository instance.
  42. *
  43. * @param \Illuminate\Database\ConnectionInterface $connection
  44. * @param \Illuminate\Contracts\Hashing\Hasher $hasher
  45. * @param string $table
  46. * @param string $hashKey
  47. * @param int $expires
  48. * @return void
  49. */
  50. public function __construct(ConnectionInterface $connection, HasherContract $hasher,
  51. $table, $hashKey, $expires = 60)
  52. {
  53. $this->table = $table;
  54. $this->hasher = $hasher;
  55. $this->hashKey = $hashKey;
  56. $this->expires = $expires * 60;
  57. $this->connection = $connection;
  58. }
  59. /**
  60. * Create a new token record.
  61. *
  62. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  63. * @return string
  64. */
  65. public function create(CanResetPasswordContract $user)
  66. {
  67. $email = $user->getEmailForPasswordReset();
  68. $this->deleteExisting($user);
  69. // We will create a new, random token for the user so that we can e-mail them
  70. // a safe link to the password reset form. Then we will insert a record in
  71. // the database so that we can verify the token within the actual reset.
  72. $token = $this->createNewToken();
  73. $this->getTable()->insert($this->getPayload($email, $token));
  74. return $token;
  75. }
  76. /**
  77. * Delete all existing reset tokens from the database.
  78. *
  79. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  80. * @return int
  81. */
  82. protected function deleteExisting(CanResetPasswordContract $user)
  83. {
  84. return $this->getTable()->where('email', $user->getEmailForPasswordReset())->delete();
  85. }
  86. /**
  87. * Build the record payload for the table.
  88. *
  89. * @param string $email
  90. * @param string $token
  91. * @return array
  92. */
  93. protected function getPayload($email, $token)
  94. {
  95. return ['email' => $email, 'token' => $this->hasher->make($token), 'created_at' => new Carbon];
  96. }
  97. /**
  98. * Determine if a token record exists and is valid.
  99. *
  100. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  101. * @param string $token
  102. * @return bool
  103. */
  104. public function exists(CanResetPasswordContract $user, $token)
  105. {
  106. $record = (array) $this->getTable()->where(
  107. 'email', $user->getEmailForPasswordReset()
  108. )->first();
  109. return $record &&
  110. ! $this->tokenExpired($record['created_at']) &&
  111. $this->hasher->check($token, $record['token']);
  112. }
  113. /**
  114. * Determine if the token has expired.
  115. *
  116. * @param string $createdAt
  117. * @return bool
  118. */
  119. protected function tokenExpired($createdAt)
  120. {
  121. return Carbon::parse($createdAt)->addSeconds($this->expires)->isPast();
  122. }
  123. /**
  124. * Delete a token record by user.
  125. *
  126. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  127. * @return void
  128. */
  129. public function delete(CanResetPasswordContract $user)
  130. {
  131. $this->deleteExisting($user);
  132. }
  133. /**
  134. * Delete expired tokens.
  135. *
  136. * @return void
  137. */
  138. public function deleteExpired()
  139. {
  140. $expiredAt = Carbon::now()->subSeconds($this->expires);
  141. $this->getTable()->where('created_at', '<', $expiredAt)->delete();
  142. }
  143. /**
  144. * Create a new token for the user.
  145. *
  146. * @return string
  147. */
  148. public function createNewToken()
  149. {
  150. return hash_hmac('sha256', Str::random(40), $this->hashKey);
  151. }
  152. /**
  153. * Get the database connection instance.
  154. *
  155. * @return \Illuminate\Database\ConnectionInterface
  156. */
  157. public function getConnection()
  158. {
  159. return $this->connection;
  160. }
  161. /**
  162. * Begin a new database query against the table.
  163. *
  164. * @return \Illuminate\Database\Query\Builder
  165. */
  166. protected function getTable()
  167. {
  168. return $this->connection->table($this->table);
  169. }
  170. /**
  171. * Get the hasher instance.
  172. *
  173. * @return \Illuminate\Contracts\Hashing\Hasher
  174. */
  175. public function getHasher()
  176. {
  177. return $this->hasher;
  178. }
  179. }