Skip to content

[11.x] Cache token repository #53428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions src/Illuminate/Auth/Passwords/CacheTokenRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

namespace Illuminate\Auth\Passwords;

use Illuminate\Cache\Repository;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

class CacheTokenRepository implements TokenRepositoryInterface
{
/**
* The format of the stored Carbon object.
*/
protected string $format = 'Y-m-d H:i:s';

/**
* Create a new token repository instance.
*/
public function __construct(
protected Repository $cache,
protected HasherContract $hasher,
protected string $hashKey,
protected int $expires = 3600,
protected int $throttle = 60
) {
}

/**
* Create a new token.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @return string
*/
public function create(CanResetPasswordContract $user)
{
$email = $user->getEmailForPasswordReset();

$this->delete($user);

$token = hash_hmac('sha256', Str::random(40), $this->hashKey);

$this->cache->put($email, [$token, Carbon::now()->format($this->format)], $this->expires);

return $token;
}

/**
* Determine if a token record exists and is valid.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @param string $token
* @return bool
*/
public function exists(CanResetPasswordContract $user, #[\SensitiveParameter] $token)
{
[$record, $createdAt] = $this->cache->get($user->getEmailForPasswordReset());

return $record
&& ! $this->tokenExpired($createdAt)
&& $this->hasher->check($token, $record);
}

/**
* Determine if the token has expired.
*
* @param string $createdAt
* @return bool
*/
protected function tokenExpired($createdAt)
{
return Carbon::createFromFormat($this->format, $createdAt)->addSeconds($this->expires)->isPast();
}

/**
* Determine if the given user recently created a password reset token.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @return bool
*/
public function recentlyCreatedToken(CanResetPasswordContract $user)
{
[$record, $createdAt] = $this->cache->get($user->getEmailForPasswordReset());

return $record && $this->tokenRecentlyCreated($createdAt);
}

/**
* Determine if the token was recently created.
*
* @param string $createdAt
* @return bool
*/
protected function tokenRecentlyCreated($createdAt)
{
if ($this->throttle <= 0) {
return false;
}

return Carbon::createFromFormat($this->format, $createdAt)->addSeconds(
$this->throttle
)->isFuture();
}

/**
* Delete a token record.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @return void
*/
public function delete(CanResetPasswordContract $user)
{
$this->cache->forget($user->getEmailForPasswordReset());
}

/**
* Delete expired tokens.
*
* @return void
*/
public function deleteExpired()
{
}
}
12 changes: 10 additions & 2 deletions src/Illuminate/Auth/Passwords/PasswordBrokerManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,18 @@ protected function createTokenRepository(array $config)
$key = base64_decode(substr($key, 7));
}

$connection = $config['connection'] ?? null;
if (isset($config['driver']) && $config['driver'] === 'cache') {
return new CacheTokenRepository(
$this->app['cache']->store($config['store'] ?? null),
$this->app['hash'],
$key,
($config['expire'] ?? 60) * 60,
$config['throttle'] ?? 0
);
}

return new DatabaseTokenRepository(
$this->app['db']->connection($connection),
$this->app['db']->connection($config['connection'] ?? null),
$this->app['hash'],
$config['table'],
$key,
Expand Down