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

Commit e7812b5

Browse files
committed
Merge branch 'develop'
2 parents 847c956 + c662d8f commit e7812b5

File tree

9 files changed

+119
-58
lines changed

9 files changed

+119
-58
lines changed

README.md

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
# Two-Factor-Authentication
1+
[![Latest Stable Version](https://poser.pugx.org/michaeldzjap/twofactor-auth/version)](https://packagist.org/packages/michaeldzjap/twofactor-auth)
2+
[![Total Downloads](https://poser.pugx.org/michaeldzjap/twofactor-auth/downloads)](https://packagist.org/packages/michaeldzjap/twofactor-auth)
3+
[![Latest Unstable Version](https://poser.pugx.org/michaeldzjap/twofactor-auth/v/unstable)](//packagist.org/packages/michaeldzjap/twofactor-auth)
4+
[![License](https://poser.pugx.org/michaeldzjap/twofactor-auth/license)](https://packagist.org/packages/michaeldzjap/twofactor-auth)
5+
6+
# laravel-two-factor-authentication
27
A two-factor authentication package for Laravel >= 5.5
38

49
## Description
@@ -92,8 +97,8 @@ and
9297
/**
9398
* Log out the user and start the two factor authentication state.
9499
*
95-
* @param Request $request
96-
* @param User $user
100+
* @param \Illuminate\Http\Request $request
101+
* @param \App\User $user
97102
* @return \Illuminate\Http\Response
98103
*/
99104
private function startTwoFactorAuthProcess(Request $request, $user)
@@ -115,7 +120,7 @@ and lastly
115120
* Provider specific two-factor authentication logic. In the case of MessageBird
116121
* we just want to send an authentication token via SMS.
117122
*
118-
* @param User $user
123+
* @param \App\User $user
119124
* @return mixed
120125
*/
121126
private function registerUserAndSendToken(User $user)
@@ -168,16 +173,15 @@ class TwoFactorAuthController extends Controller
168173
```php
169174
...
170175
<form class="form-horizontal" role="form" method="POST" action="{{ route('login') }}">
171-
{{ csrf_field() }}
176+
@csrf
172177

173178
{{-- Add this block to show an error message in case of an expired token or user lockout --}}
174179
@if ($errors->has('token'))
175-
<div class="form-group has-error">
176-
<div class="col-xs-12">
177-
<span class="help-block">
178-
<strong>{{ $errors->first('token') }}</strong>
179-
</span>
180-
</div>
180+
<div class="alert alert-danger alert-dismissible fade show" role="alert">
181+
<strong>{{ $errors->first('token') }}</strong>
182+
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
183+
<span aria-hidden="true">&times;</span>
184+
</button>
181185
</div>
182186
@endif
183187
...
@@ -207,3 +211,6 @@ TWO_FACTOR_AUTH_DRIVER=dummy
207211

208212
## Errors and Exceptions
209213
Unfortunately the *MessageBird* php api throws rather generic exceptions when the verification of a token fails. The only way to distinguish an expired token from an invalid token is by comparing their error messages, which obviously is not a very robust mechanism. The reason this is rather unfortunate is because in the case of an invalid token we want to give the user at least a few (3) changes to re-enter the token before throttling kicks in, whereas in the case of an expired token we just want to redirect to the login screen right away.
214+
215+
## Testing
216+
An example project including unit and browser tests can be found [here](https://github.com/michaeldzjap/laravel-two-factor-authentication-example).
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace MichaelDzjap\TwoFactorAuth\Events;
4+
5+
use App\User;
6+
use Illuminate\Queue\SerializesModels;
7+
8+
class TwoFactorAuthenticated
9+
{
10+
use SerializesModels;
11+
12+
/**
13+
* The user instance.
14+
*
15+
* @var \App\User
16+
*/
17+
public $user;
18+
19+
/**
20+
* Create a new event instance.
21+
*
22+
* @param \App\User $user
23+
* @return void
24+
*/
25+
public function __construct(User $user)
26+
{
27+
$this->user = $user;
28+
}
29+
}

src/Http/Controllers/TwoFactorAuthenticatesUsers.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Http\Request;
88
use Illuminate\Validation\ValidationException;
99
use MichaelDzjap\TwoFactorAuth\Contracts\TwoFactorProvider;
10+
use MichaelDzjap\TwoFactorAuth\Events\TwoFactorAuthenticated;
1011
use MichaelDzjap\TwoFactorAuth\Exceptions\TokenAlreadyProcessedException;
1112
use MichaelDzjap\TwoFactorAuth\Exceptions\TokenExpiredException;
1213
use MichaelDzjap\TwoFactorAuth\Exceptions\TokenInvalidException;
@@ -100,7 +101,24 @@ protected function sendTwoFactorAuthResponse(Request $request)
100101

101102
$request->session()->forget('two-factor:auth');
102103

103-
return redirect()->intended($this->redirectPath());
104+
$user = $request->user();
105+
106+
event(new TwoFactorAuthenticated($user));
107+
108+
return $this->authenticated($request, $user)
109+
?: redirect()->intended($this->redirectPath());
110+
}
111+
112+
/**
113+
* The user has been two-factor authenticated.
114+
*
115+
* @param \Illuminate\Http\Request $request
116+
* @param mixed $user
117+
* @return mixed
118+
*/
119+
protected function authenticated(Request $request, $user)
120+
{
121+
//
104122
}
105123

106124
/**
@@ -109,6 +127,7 @@ protected function sendTwoFactorAuthResponse(Request $request)
109127
* we can only do it here because we don't need to redirect to the login route.
110128
*
111129
* @param \Illuminate\Http\Request $request
130+
*
112131
* @throws \Illuminate\Validation\ValidationException
113132
*/
114133
protected function sendFailedTwoFactorAuthResponse(Request $request)

src/Providers/BaseProvider.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace MichaelDzjap\TwoFactorAuth\Providers;
4+
5+
use App\User;
6+
7+
abstract class BaseProvider
8+
{
9+
/**
10+
* Check if two-factor authentication is enabled for a user.
11+
*
12+
* @param \App\User $user
13+
* @return bool
14+
*/
15+
public function enabled(User $user)
16+
{
17+
return !is_null($user->twoFactorAuth);
18+
}
19+
}

src/Providers/MessageBirdVerify.php

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use MichaelDzjap\TwoFactorAuth\Exceptions\TokenExpiredException;
1414
use MichaelDzjap\TwoFactorAuth\Exceptions\TokenInvalidException;
1515

16-
class MessageBirdVerify implements TwoFactorProvider, SMSToken
16+
class MessageBirdVerify extends BaseProvider implements TwoFactorProvider, SMSToken
1717
{
1818
/**
1919
* MessageBird client instance.
@@ -25,29 +25,18 @@ class MessageBirdVerify implements TwoFactorProvider, SMSToken
2525
/**
2626
* MessageBirdVerify constructor.
2727
*
28-
* @param Client $client
28+
* @param \MessageBird\Client $client
2929
* @return void
3030
*/
3131
public function __construct(Client $client)
3232
{
3333
$this->client = $client;
3434
}
3535

36-
/**
37-
* Check if two-factor authentication is enabled for a user.
38-
*
39-
* @param User $user
40-
* @return bool
41-
*/
42-
public function enabled(User $user)
43-
{
44-
return $user->twoFactorAuth;
45-
}
46-
4736
/**
4837
* Register a user with this provider.
4938
*
50-
* @param User $user
39+
* @param \App\User $user
5140
* @return void
5241
*/
5342
public function register(User $user)
@@ -58,7 +47,7 @@ public function register(User $user)
5847
/**
5948
* Unregister a user with this provider.
6049
*
61-
* @param User $user
50+
* @param \App\User $user
6251
* @return bool
6352
*/
6453
public function unregister(User $user)
@@ -72,8 +61,8 @@ public function unregister(User $user)
7261
/**
7362
* Determine if the token is valid.
7463
*
75-
* @param User $user
76-
* @param string $token
64+
* @param \App\User $user
65+
* @param string $token
7766
* @return bool
7867
*/
7968
public function verify(User $user, string $token)
@@ -115,11 +104,11 @@ public function verify(User $user, string $token)
115104
/**
116105
* Send a user a two-factor authentication token via SMS.
117106
*
118-
* @param User $user
107+
* @param \App\User $user
119108
* @return void
120-
* @throws Exception $exception
109+
* @throws Exception $exception
121110
*/
122-
public function sendSMSToken(User $user)
111+
public function sendSMSToken(User $user) : void
123112
{
124113
if (!$user->mobile) {
125114
throw new Exception("No mobile phone number found for user {$user->id}.");

src/Providers/NullProvider.php

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,8 @@
66
use MichaelDzjap\TwoFactorAuth\Contracts\SMSToken;
77
use MichaelDzjap\TwoFactorAuth\Contracts\TwoFactorProvider;
88

9-
class NullProvider implements TwoFactorProvider, SMSToken
9+
class NullProvider extends BaseProvider implements TwoFactorProvider, SMSToken
1010
{
11-
/**
12-
* {@inheritdoc}
13-
*/
14-
public function enabled(User $user)
15-
{
16-
return $user->twoFactorAuth;
17-
}
18-
1911
/**
2012
* {@inheritdoc}
2113
*/

src/TwoFactorAuth.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace MichaelDzjap\TwoFactorAuth;
44

5-
use App\User;
5+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
66
use Illuminate\Database\Eloquent\Model;
77

88
class TwoFactorAuth extends Model
@@ -34,9 +34,11 @@ class TwoFactorAuth extends Model
3434

3535
/**
3636
* Get the user that owns the two-factor auth.
37+
*
38+
* @param \Illuminate\Database\Eloquent\Relations\BelongsTo
3739
*/
38-
public function user()
40+
public function user() : BelongsTo
3941
{
40-
return $this->belongsTo(User::class);
42+
return $this->belongsTo(\App\User::class);
4143
}
4244
}

src/TwoFactorAuthenticable.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33
namespace MichaelDzjap\TwoFactorAuth;
44

5+
use Illuminate\Database\Eloquent\Relations\HasOne;
56
use MichaelDzjap\TwoFactorAuth\TwoFactorAuth;
67

78
trait TwoFactorAuthenticable
89
{
910
/**
1011
* Get the two-factor auth record associated with the user.
12+
*
13+
* @return \Illuminate\Database\Eloquent\Relations\HasOne
1114
*/
12-
public function twoFactorAuth()
15+
public function twoFactorAuth() : HasOne
1316
{
1417
return $this->hasOne(TwoFactorAuth::class);
1518
}
@@ -20,7 +23,7 @@ public function twoFactorAuth()
2023
* @param string $id
2124
* @return void
2225
*/
23-
public function setTwoFactorAuthId(string $id)
26+
public function setTwoFactorAuthId(string $id) : void
2427
{
2528
$this->twoFactorAuth->update(['id' => $id]);
2629
}

src/resources/views/form.blade.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,31 @@
22

33
@section('content')
44
<div class="container">
5-
<div class="row">
6-
<div class="col-md-8 col-md-offset-2">
7-
<div class="panel panel-default">
8-
<div class="panel-heading">@lang('twofactor-auth::twofactor-auth.title')</div>
9-
<div class="panel-body">
5+
<div class="row justify-content-center">
6+
<div class="col-md-8">
7+
<div class="card">
8+
<div class="card-header">@lang('twofactor-auth::twofactor-auth.title')</div>
9+
10+
<div class="card-body">
1011
<form class="form-horizontal" role="form" method="POST" action="{{ route('auth.token') }}">
11-
{{ csrf_field() }}
12+
@csrf
1213

13-
<div class="form-group{{ $errors->has('token') ? ' has-error' : '' }}">
14-
<label for="token" class="col-md-4 control-label">@lang('twofactor-auth::twofactor-auth.label')</label>
14+
<div class="form-group row">
15+
<label for="token" class="col-md-4 col-form-label text-md-right">@lang('twofactor-auth::twofactor-auth.label')</label>
1516

1617
<div class="col-md-6">
17-
<input id="token" type="text" class="form-control" name="token" value="{{ old('token') }}" required autofocus>
18+
<input id="token" type="text" class="form-control{{ $errors->has('token') ? ' is-invalid' : '' }}" name="token" value="{{ old('token') }}" required autofocus>
1819

1920
@if ($errors->has('token'))
20-
<span class="help-block">
21+
<span class="invalid-feedback" role="alert">
2122
<strong>{{ $errors->first('token') }}</strong>
2223
</span>
2324
@endif
2425
</div>
2526
</div>
2627

27-
<div class="form-group">
28-
<div class="col-md-8 col-md-offset-4">
28+
<div class="form-group row mb-0">
29+
<div class="col-md-8 offset-md-4">
2930
<button type="submit" class="btn btn-primary">
3031
@lang('twofactor-auth::twofactor-auth.send')
3132
</button>

0 commit comments

Comments
 (0)