Skip to content
This repository was archived by the owner on Apr 19, 2025. It is now read-only.

Commit 2fb43f8

Browse files
committed
Merge branch 'release/3.1.0' into master
2 parents 250b7e2 + 09ad408 commit 2fb43f8

File tree

5 files changed

+100
-26
lines changed

5 files changed

+100
-26
lines changed

README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ A two-factor authentication package for _Laravel_ >= 8 (for Laravel 5 to 7 you w
1212

1313
- [Description](#description)
1414
- [Important](#important)
15+
- [Optional Correction](#optional-correction)
1516
- [Installation](#installation)
1617
- [Changes to the Login Process](#changes-to-the-login-process)
18+
- [Failed Verification Attempt Handling](#failed-verification-attempt-handling)
1719
- [Using a Custom Provider](#using-a-custom-provider)
1820
- [Errors and Exceptions](#errors-and-exceptions)
1921
- [Testing](#testing)
@@ -30,7 +32,7 @@ From _Laravel_ 5.8 and onwards, the default is to use `bigIncrements` instead of
3032

3133
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.
3234

33-
### Optional correction
35+
### Optional Correction
3436
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
3537

3638
```php
@@ -216,6 +218,7 @@ The first route is the route the user will be redirected to once the two-factor
216218
namespace App\Http\Controllers\Auth;
217219

218220
use App\Http\Controllers\Controller;
221+
use App\Providers\RouteServiceProvider;
219222
use MichaelDzjap\TwoFactorAuth\Http\Controllers\TwoFactorAuthenticatesUsers;
220223

221224
class TwoFactorAuthController extends Controller
@@ -241,7 +244,7 @@ The first route is the route the user will be redirected to once the two-factor
241244
*
242245
* @var string
243246
*/
244-
protected $redirectTo = '/home';
247+
protected $redirectTo = RouteServiceProvider::HOME;
245248
}
246249
```
247250
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
262265
...
263266
```
264267

268+
### Failed Verification Attempt Handling
269+
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.
270+
271+
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:
272+
```php
273+
<?php
274+
275+
namespace App\Http\Controllers\Auth;
276+
277+
use App\Http\Controllers\Controller;
278+
use App\Providers\RouteServiceProvider;
279+
use MichaelDzjap\TwoFactorAuth\Http\Controllers\TwoFactorAuthenticatesUsers;
280+
281+
class TwoFactorAuthController extends Controller
282+
{
283+
use TwoFactorAuthenticatesUsers;
284+
285+
/**
286+
* Where to redirect users after two-factor authentication passes.
287+
*
288+
* @var string
289+
*/
290+
protected $redirectTo = RouteServiceProvider::HOME;
291+
292+
/**
293+
* Where to redirect users after two-factor authentication fails.
294+
*
295+
* @var string
296+
*/
297+
protected $redirectToAfterFailure = '/login';
298+
}
299+
```
300+
Redirecting a user to a route for generating a fresh authentication token would require a bit more work, but certainly is possible this way.
301+
265302
## Using a Custom Provider
266303
Since the v2.1.0 release it is possible to user your own custom provider. To do so your provider needs to implement `MichaelDzjap\TwoFactorAuth\Contracts\TwoFactorProvider` (and possibly `MichaelDzjap\TwoFactorAuth\Contracts\SMSToken` if you want to send the authentication token via SMS).
267304

src/database/factories/TwoFactorAuthFactory.php renamed to src/Factories/TwoFactorAuthFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace MichaelDzjap\TwoFactorAuth\Database\Factories;
3+
namespace MichaelDzjap\TwoFactorAuth\Factories;
44

55
use Illuminate\Database\Eloquent\Factories\Factory;
66
use MichaelDzjap\TwoFactorAuth\Models\TwoFactorAuth;

src/Http/Controllers/TwoFactorAuthenticatesUsers.php

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,7 @@ public function verifyToken(VerifySMSToken $request)
5858
return $this->sendTwoFactorAuthResponse($request);
5959
}
6060

61-
// If the two-factor authentication attempt was unsuccessful we will increment
62-
// the number of attempts to two-factor authenticate and redirect the user
63-
// back to the two-factor authentication form. Of course, when this user
64-
// surpasses their maximum number of attempts they will get locked out.
65-
$this->incrementTwoFactorAuthAttempts($request);
66-
67-
return $this->sendFailedTwoFactorAuthResponse($request);
61+
return $this->handleFailedAttempt($request);
6862
}
6963

7064
/**
@@ -122,6 +116,49 @@ protected function authenticated(Request $request, $user)
122116
//
123117
}
124118

119+
/**
120+
* Handle the case where a user has submitted an invalid token.
121+
*
122+
* Default: If the two-factor authentication attempt was unsuccessful we
123+
* will increment the number of attempts to two-factor authenticate and
124+
* redirect the user back to the two-factor authentication form. Of course,
125+
* when this user surpasses their maximum number of attempts they will get
126+
* locked out.
127+
*
128+
* @param \Illuminate\Http\Request $request
129+
* @return \Illuminate\Http\Response
130+
*/
131+
protected function handleFailedAttempt(Request $request)
132+
{
133+
$this->incrementTwoFactorAuthAttempts($request);
134+
135+
if ($path = $this->redirectAfterFailurePath()) {
136+
return redirect()->to($path)->withErrors([
137+
'token' => __('twofactor-auth::twofactor-auth.failed'),
138+
]);
139+
}
140+
141+
return $this->sendFailedTwoFactorAuthResponse($request);
142+
}
143+
144+
/**
145+
* Get the post two-factor authentication failure redirect path.
146+
*
147+
* @return null|string
148+
*/
149+
protected function redirectAfterFailurePath(): ?string
150+
{
151+
if (method_exists($this, 'redirectToAfterFailure')) {
152+
return $this->redirectToAfterFailure();
153+
}
154+
155+
if (property_exists($this, 'redirectToAfterFailure')) {
156+
return $this->redirectToAfterFailure;
157+
}
158+
159+
return null;
160+
}
161+
125162
/**
126163
* Throw a validation exception when two-factor authentication attempt fails.
127164
* NOTE: Throwing a validation exception is cleaner than redirecting, but

src/Models/TwoFactorAuth.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,6 @@ private function model(): string
7676
*/
7777
protected static function newFactory(): Factory
7878
{
79-
return \MichaelDzjap\TwoFactorAuth\Database\Factories\TwoFactorAuthFactory::new();
79+
return \MichaelDzjap\TwoFactorAuth\Factories\TwoFactorAuthFactory::new();
8080
}
8181
}

src/config/twofactor-auth.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,6 @@
22

33
return [
44

5-
/*
6-
|--------------------------------------------------------------------------
7-
| Enabled
8-
|--------------------------------------------------------------------------
9-
|
10-
| Options:
11-
|
12-
| - 'always': Always require two-factor authentication.
13-
| - 'never': Never require two-factor authentication.
14-
| - 'user': Specify manually for which users to enable 2fa.
15-
|
16-
*/
17-
18-
'enabled' => 'user',
19-
205
/*
216
|--------------------------------------------------------------------------
227
| Default Two-Factor Authentication Provider
@@ -61,6 +46,21 @@
6146

6247
],
6348

49+
/*
50+
|--------------------------------------------------------------------------
51+
| Enabled Mode
52+
|--------------------------------------------------------------------------
53+
|
54+
| Options:
55+
|
56+
| 'always': Always require two-factor authentication.
57+
| 'never': Never require two-factor authentication.
58+
| 'user': Specify manually for which users to enable 2fa.
59+
|
60+
*/
61+
62+
'enabled' => 'user',
63+
6464
/*
6565
|--------------------------------------------------------------------------
6666
| Routes Configuration + Naming

0 commit comments

Comments
 (0)