Skip to content

Commit b9e2c45

Browse files
committed
Change AuthUserProvider API to support api token authentication.
1 parent 2d2a063 commit b9e2c45

File tree

4 files changed

+261
-21
lines changed

4 files changed

+261
-21
lines changed

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,39 @@ public function boot()
286286
$this->registerPolicies();
287287

288288
Auth::provider('dynamodb', function ($app, array $config) {
289-
return new AuthUserProvider(new $config['model']);
289+
return new AuthUserProvider(
290+
$app['hash'],
291+
$config['model'],
292+
$config['api_token_name'] ?? null,
293+
$config['api_token_index'] ?? null
294+
);
290295
});
291296
}
292297
```
293298

299+
### Modify LoginController
300+
301+
The default authentication uses the `email` and `password` column to validate, which is not the primary key of the table. However, DynamoDB needs to use the primary key to identify, so we need to tweak the LoginController a bit.
302+
303+
```php
304+
namespace App\Http\Controllers\Auth;
305+
306+
class LoginController extends Controller
307+
{
308+
...
309+
310+
/**
311+
* Get the login username to be used by the controller.
312+
*
313+
* @return string
314+
*/
315+
public function username()
316+
{
317+
return 'your-primary-key';
318+
}
319+
}
320+
```
321+
294322
### Change auth config
295323

296324
Then specify driver and model name for authentication in `config/auth.php`.
@@ -307,10 +335,14 @@ Then specify driver and model name for authentication in `config/auth.php`.
307335
'users' => [
308336
'driver' => 'dynamodb',
309337
'model' => App\User::class,
338+
'api_token_name' => 'api_token',
339+
'api_token_index' => 'api_token-index'
310340
],
311341
],
312342
```
313343

344+
`api_token_name` and `api_token_index` are optional, but we need them if we use api token authentication.
345+
314346
## Query Builder
315347

316348
We can use Query Builder without model.
@@ -566,6 +598,14 @@ $response = DB::table('ProductCatalog')
566598
->scan();
567599
```
568600

601+
If you are using Query Builder through model, you can access to `exclusiveStartKey` by:
602+
603+
```php
604+
$products = ProductCatalog::limit(5)->scan();
605+
606+
$products->first()->meta()['LastEvaluatedKey']; // array
607+
```
608+
569609
### Using Global Secondary Indexes
570610

571611
Some applications might need to perform many kinds of queries, using a variety of different attributes as query criteria. To support these requirements, you can create one or more global secondary indexes and issue `query` requests against these indexes in Amazon DynamoDB.

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"illuminate/support": "^6.0|^7.0",
2525
"illuminate/container": "^6.0|^7.0",
2626
"illuminate/database": "^6.0|^7.0",
27+
"illuminate/hashing": "^6.0|^7.0",
2728
"aws/aws-sdk-php": "^3.0"
2829
},
2930
"require-dev": {

src/Kitar/Dynamodb/Model/AuthUserProvider.php

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,44 @@
44

55
use Illuminate\Contracts\Auth\Authenticatable;
66
use Illuminate\Contracts\Auth\UserProvider as BaseUserProvider;
7-
use Illuminate\Support\Facades\Hash;
7+
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
88

99
class AuthUserProvider implements BaseUserProvider
1010
{
11+
/**
12+
* The hasher implementation.
13+
*
14+
* @var \Illuminate\Contracts\Hashing\Hasher
15+
*/
16+
protected $hasher;
17+
18+
/**
19+
* The Eloquent user model.
20+
*
21+
* @var string
22+
*/
1123
protected $model;
1224

13-
public function __construct(Authenticatable $model)
25+
/**
26+
* The column name of the api token.
27+
*
28+
* @var string
29+
*/
30+
protected $apiTokenName;
31+
32+
/**
33+
* The index name to use when querying by api token.
34+
*
35+
* @var string
36+
*/
37+
protected $apiTokenIndex;
38+
39+
public function __construct(HasherContract $hasher, $model, $apiTokenName = null, $apiTokenIndex = null)
1440
{
1541
$this->model = $model;
42+
$this->hasher = $hasher;
43+
$this->apiTokenName = $apiTokenName;
44+
$this->apiTokenIndex = $apiTokenIndex;
1645
}
1746

1847
/**
@@ -23,7 +52,9 @@ public function __construct(Authenticatable $model)
2352
*/
2453
public function retrieveById($identifier)
2554
{
26-
return $this->model->find($identifier);
55+
$model = $this->createModel();
56+
57+
return $model->find($identifier);
2758
}
2859

2960
/**
@@ -37,9 +68,14 @@ public function retrieveByToken($identifier, $token)
3768
{
3869
$user = $this->retrieveById($identifier);
3970

40-
if ($user && $user->getRememberToken() == $token) {
41-
return $user;
71+
if (! $user) {
72+
return;
4273
}
74+
75+
$rememberToken = $user->getRememberToken();
76+
77+
return $rememberToken && hash_equals($rememberToken, $token)
78+
? $user : null;
4379
}
4480

4581
/**
@@ -52,17 +88,49 @@ public function retrieveByToken($identifier, $token)
5288
public function updateRememberToken(Authenticatable $user, $token)
5389
{
5490
$user->setRememberToken($token);
91+
92+
$timestamps = $user->timestamps;
93+
94+
$user->timestamps = false;
95+
96+
$user->save();
97+
98+
$user->timestamps = $timestamps;
5599
}
56100

57101
/**
58102
* Retrieve a user by the given credentials.
103+
* Identifier or API Token are supported.
59104
*
60105
* @param array $credentials
61106
* @return \Illuminate\Contracts\Auth\Authenticatable|null
62107
*/
63108
public function retrieveByCredentials(array $credentials)
64109
{
65-
return $this->retrieveById($credentials['email']);
110+
if (isset($credentials['password'])) {
111+
unset($credentials['password']);
112+
}
113+
114+
if (count($credentials) !== 1) {
115+
return;
116+
}
117+
118+
$model = $this->createModel();
119+
120+
$id = $credentials[$model->getAuthIdentifierName()] ?? null;
121+
122+
if ($id) {
123+
return $this->retrieveById($id);
124+
}
125+
126+
$apiToken = $this->apiTokenName ? $credentials[$this->apiTokenName] ?? null : null;
127+
128+
if ($apiToken && $this->apiTokenIndex) {
129+
return $model->index($this->apiTokenIndex)
130+
->keyCondition($this->apiTokenName, '=', $apiToken)
131+
->query()
132+
->first();
133+
}
66134
}
67135

68136
/**
@@ -74,6 +142,20 @@ public function retrieveByCredentials(array $credentials)
74142
*/
75143
public function validateCredentials(Authenticatable $user, array $credentials)
76144
{
77-
return Hash::check($credentials['password'], $user->password);
145+
$plain = $credentials['password'];
146+
147+
return $this->hasher->check($plain, $user->getAuthPassword());
148+
}
149+
150+
/**
151+
* Create a new instance of the model.
152+
*
153+
* @return \Kitar\Dynamodb\Model\Model
154+
*/
155+
public function createModel()
156+
{
157+
$class = '\\'.ltrim($this->model, '\\');
158+
159+
return new $class;
78160
}
79161
}

0 commit comments

Comments
 (0)