diff --git a/README.md b/README.md index 96e9124..c0ef0e4 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,10 @@ A two-factor authentication package for _Laravel_ >= 8 (for Laravel 5 to 7 you w - [Description](#description) - [Important](#important) + - [Optional Correction](#optional-correction) - [Installation](#installation) - [Changes to the Login Process](#changes-to-the-login-process) + - [Failed Verification Attempt Handling](#failed-verification-attempt-handling) - [Using a Custom Provider](#using-a-custom-provider) - [Errors and Exceptions](#errors-and-exceptions) - [Testing](#testing) @@ -30,7 +32,7 @@ From _Laravel_ 5.8 and onwards, the default is to use `bigIncrements` instead of Publishing the package's migration files allows for more flexibility with regards to customising your database structure. However, it could also cause complications if you already have ran migrations as part of installing previous versions of this package. In this case you simply might want to bypass running the migrations again or only run them when in a specific environment. The `Schema::hasColumn()` and `Schema::hasTable()` methods should be of use here. -### Optional correction +### Optional Correction Versions of this package prior to v2.3.0 incorrectly created the `user_id` column on the `two_factor_auths` table using `increments` instead of `unsignedInteger`. Practically speaking, this error is of no concern. Although there is no need to have a _primary_ key for the `user_id` column, it doesn't cause any problems either. However, if for some reason you don't like this idea, it is safe to remove the _primary_ key using a migration of the form ```php @@ -216,6 +218,7 @@ The first route is the route the user will be redirected to once the two-factor namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; + use App\Providers\RouteServiceProvider; use MichaelDzjap\TwoFactorAuth\Http\Controllers\TwoFactorAuthenticatesUsers; class TwoFactorAuthController extends Controller @@ -241,7 +244,7 @@ The first route is the route the user will be redirected to once the two-factor * * @var string */ - protected $redirectTo = '/home'; + protected $redirectTo = RouteServiceProvider::HOME; } ``` 3. If you want to give textual feedback to the user when two-factor authentication fails due to an expired token or when throttling kicks in you may want to add this to `resources/views/auth/login.blade.php`: @@ -262,6 +265,40 @@ The first route is the route the user will be redirected to once the two-factor ... ``` +### Failed Verification Attempt Handling +The default behaviour is to redirect to the previous view with an error message in case token verification fails. However, there most likely are instances where you would like to handle a failed token verification attempt differently. For instance, in the case of _MessageBird_ a token can only be verified once. Any attempt with the same token after a first failed attempt will always throw a `TokenAlreadyProcessedException` and hence, it would make more sense to either redirect to the _/login_ route again to start the entire authentication process from scratch or to redirect to a view where a new token can be requested. + +In order to change the default behaviour it is possible to specify either a `$redirectToAfterFailure` property or a protected `redirectToAfterFailure` method on your `TwoFactorAuthController`. If one of these is present (the method taking precedence over the property), the default behaviour is bypassed and the user will be redirected to the specified route. To give a simple example, suppose you simply want to redirect to the _/login_ route after a failed verification attempt you would structure your `TwoFactorAuthController` like: +```php +sendTwoFactorAuthResponse($request); } - // If the two-factor authentication attempt was unsuccessful we will increment - // the number of attempts to two-factor authenticate and redirect the user - // back to the two-factor authentication form. Of course, when this user - // surpasses their maximum number of attempts they will get locked out. - $this->incrementTwoFactorAuthAttempts($request); - - return $this->sendFailedTwoFactorAuthResponse($request); + return $this->handleFailedAttempt($request); } /** @@ -122,6 +116,49 @@ protected function authenticated(Request $request, $user) // } + /** + * Handle the case where a user has submitted an invalid token. + * + * Default: If the two-factor authentication attempt was unsuccessful we + * will increment the number of attempts to two-factor authenticate and + * redirect the user back to the two-factor authentication form. Of course, + * when this user surpasses their maximum number of attempts they will get + * locked out. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + protected function handleFailedAttempt(Request $request) + { + $this->incrementTwoFactorAuthAttempts($request); + + if ($path = $this->redirectAfterFailurePath()) { + return redirect()->to($path)->withErrors([ + 'token' => __('twofactor-auth::twofactor-auth.failed'), + ]); + } + + return $this->sendFailedTwoFactorAuthResponse($request); + } + + /** + * Get the post two-factor authentication failure redirect path. + * + * @return null|string + */ + protected function redirectAfterFailurePath(): ?string + { + if (method_exists($this, 'redirectToAfterFailure')) { + return $this->redirectToAfterFailure(); + } + + if (property_exists($this, 'redirectToAfterFailure')) { + return $this->redirectToAfterFailure; + } + + return null; + } + /** * Throw a validation exception when two-factor authentication attempt fails. * NOTE: Throwing a validation exception is cleaner than redirecting, but diff --git a/src/Models/TwoFactorAuth.php b/src/Models/TwoFactorAuth.php index ba2677f..8dff113 100644 --- a/src/Models/TwoFactorAuth.php +++ b/src/Models/TwoFactorAuth.php @@ -76,6 +76,6 @@ private function model(): string */ protected static function newFactory(): Factory { - return \MichaelDzjap\TwoFactorAuth\Database\Factories\TwoFactorAuthFactory::new(); + return \MichaelDzjap\TwoFactorAuth\Factories\TwoFactorAuthFactory::new(); } } diff --git a/src/config/twofactor-auth.php b/src/config/twofactor-auth.php index cf11fbc..093728a 100644 --- a/src/config/twofactor-auth.php +++ b/src/config/twofactor-auth.php @@ -2,21 +2,6 @@ return [ - /* - |-------------------------------------------------------------------------- - | Enabled - |-------------------------------------------------------------------------- - | - | Options: - | - | - 'always': Always require two-factor authentication. - | - 'never': Never require two-factor authentication. - | - 'user': Specify manually for which users to enable 2fa. - | - */ - - 'enabled' => 'user', - /* |-------------------------------------------------------------------------- | Default Two-Factor Authentication Provider @@ -61,6 +46,21 @@ ], + /* + |-------------------------------------------------------------------------- + | Enabled Mode + |-------------------------------------------------------------------------- + | + | Options: + | + | 'always': Always require two-factor authentication. + | 'never': Never require two-factor authentication. + | 'user': Specify manually for which users to enable 2fa. + | + */ + + 'enabled' => 'user', + /* |-------------------------------------------------------------------------- | Routes Configuration + Naming