I've been looking over a simple way of making a couple of minor amends to the Auth\Passwords in a project and have spotted that PasswordBrokerManager createTokenRepository() news a DatabaseTokenRepository() instance rather than resolving the \Illuminate\Auth\Passwords\TokenRepositoryInterface (which would be expected from the docblock).
Likewise the PasswordBrokerManager resolve() method new's an \Illuminate\Contracts\Auth\PasswordBroker instance (which is is in the IOC as auth.password).
I was looking at overriding a couple of methods and rebinding a new implementation of TokenRepositoryInterface before realising that this wasn't always used (only when type hinted in the construct).
What I'm asking is there a specific reason we are newing instances of contract implemenations which if were resolved, could be overridden? And if there is no reason, would a PR to change this behaviour be accepted.
I'd rather not create all the boilerplate of a new PasswordResetServiceProvider for what would be a couple of methods to override.
Funny, I just ended up in the exact same place looking for a way to do username based password resets.
The column email seems to be hard coded in DatabaseTokenRepository making this a bit more difficult than I was hoping for.
Ended up there initially because need to change the hash length (nothing
too difficult we thought!) And then discovered an awful lot which is quite
concrete!
On 2 Sep 2016 20:22, "Dave" [email protected] wrote:
Funny, I just ended up in the exact same place looking for a way to do
username based password resets.The column email seems to be hard coded in DatabaseTokenRepository making
this a bit more difficult than I was hoping for.—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/laravel/framework/issues/15071#issuecomment-244465609,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AB0I4_z-41gNMfhrgVdFVieg3udmnYO0ks5qmHeSgaJpZM4JuIrM
.
Please feel free to open a PR with the suggested changes, I think you have a point here.
Closing this since it's not actually a bug :) please ping me if you think otherwise.
This is probably irrelevant once 5.5 is released because of #17499 but I wanted to modify the Reset Password functionality so it would not generate a new token each time a user clicks the link. If a user is impatient and clicks the Reset Password more than once, then the first email they receive is now invalid because the token was replaced. Instead, I just want the 2nd email to contain the same token as the first email did.
I subclassed DatabaseTokenRepository so it will only create a new token if a non-expired one doesn't already exist.
Here's what I had to do for this to work:
config/app.php: - comment out the PasswordResetServiceProvider and replace it with my subclass:
//Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
App\Auth\Passwords\MLPasswordResetServiceProvider::class,
MLPasswordResetServiceProvider.php - which registers my MLPasswordBrokerManager in the container under auth.password:
class MLPasswordResetServiceProvider extends PasswordResetServiceProvider
{
/**
* Register the password broker instance.
*
* @return void
*/
protected function registerPasswordBroker()
{
$this->app->singleton('auth.password', function ($app) {
return new MLPasswordBrokerManager($app);
});
$this->app->bind('auth.password.broker', function ($app) {
return $app->make('auth.password')->broker();
});
}
}
MLPasswordBrokerManager.php - this class returns my MLDatabaseTokenRepository subclass:
class MLPasswordBrokerManager extends PasswordBrokerManager
{
/**
* Create a token repository instance based on the given configuration.
*
* @param array $config
* @return \Illuminate\Auth\Passwords\TokenRepositoryInterface
*/
protected function createTokenRepository(array $config)
{
$key = $this->app['config']['app.key'];
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$connection = isset($config['connection']) ? $config['connection'] : null;
return new MLDatabaseTokenRepository(
$this->app['db']->connection($connection),
$this->app['hash'],
$config['table'],
$key,
$config['expire']
);
}
}
MLDatabaseTokenRepository.php - only creates a new token if a valid one does not already exist for the user:
class MLDatabaseTokenRepository extends DatabaseTokenRepository
{
/**
* Create a new token record.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $user
* @return string
*/
public function create(CanResetPasswordContract $user)
{
$email = $user->getEmailForPasswordReset();
// If the user already has a valid token, send it instead of creating a new one.
// This will prevent the impatient user from being frustrated if they clicked
// Reset Password more than once.
$record = (array)$this->getTable()
->where('email', $email)
->first();
$exists = $record && !$this->tokenExpired($record['created_at']);
if ($exists) {
return $record['token'];
}
$this->deleteExisting($user);
// We will create a new, random token for the user so that we can e-mail them
// a safe link to the password reset form. Then we will insert a record in
// the database so that we can verify the token within the actual reset.
$token = $this->createNewToken();
$this->getTable()->insert($this->getPayload($email, $token));
return $token;
}
}
Hi,
Resolving TokenRepositoryInterface instance should permits to easily implements token management with Sentinel Reminder.
L5.4 has new DatabaseTokenRepository() hard coded.
Cheers.
Most helpful comment
This is probably irrelevant once 5.5 is released because of #17499 but I wanted to modify the Reset Password functionality so it would not generate a new token each time a user clicks the link. If a user is impatient and clicks the Reset Password more than once, then the first email they receive is now invalid because the token was replaced. Instead, I just want the 2nd email to contain the same token as the first email did.
I subclassed
DatabaseTokenRepositoryso it will only create a new token if a non-expired one doesn't already exist.Here's what I had to do for this to work:
config/app.php: - comment out thePasswordResetServiceProviderand replace it with my subclass:MLPasswordResetServiceProvider.php- which registers myMLPasswordBrokerManagerin the container underauth.password:MLPasswordBrokerManager.php- this class returns myMLDatabaseTokenRepositorysubclass:MLDatabaseTokenRepository.php- only creates a new token if a valid one does not already exist for the user: