Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 56dcee8

Browse files
committed
Configurable response factory
PSR-17 response factory can be provided in configuration
1 parent 2257aac commit 56dcee8

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,18 @@ $app->add(new Tuupola\Middleware\JwtAuthentication([
229229
]));
230230
```
231231

232+
### Response Factory
233+
234+
A custom PSR-17 compatible response factory can be provided. If none is provided, PSR-17 implementation auto-discovery is used. Response factory is used to create a new 401 response.
235+
236+
```php
237+
$app = new Slim\App;
238+
239+
$app->add(new Tuupola\Middleware\JwtAuthentication([
240+
"responseFactory" => new MyResponseFactory,
241+
]));
242+
```
243+
232244
### Rules
233245

234246
The optional `rules` parameter allows you to pass in rules which define whether the request should be authenticated or not. A rule is a callable which receives the request as parameter. If any of the rules returns boolean `false` the request will not be authenticated.

src/JwtAuthentication.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939
use InvalidArgumentException;
4040
use Exception;
4141
use Firebase\JWT\JWT;
42+
use Psr\Http\Message\ResponseFactoryInterface;
4243
use Psr\Http\Message\ServerRequestInterface;
4344
use Psr\Http\Message\ResponseInterface;
4445
use Psr\Http\Server\MiddlewareInterface;
4546
use Psr\Http\Server\RequestHandlerInterface;
4647
use Psr\Log\LoggerInterface;
4748
use Psr\Log\LogLevel;
4849
use RuntimeException;
49-
use Tuupola\Middleware\DoublePassTrait;
5050
use Tuupola\Http\Factory\ResponseFactory;
5151
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
5252
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
@@ -85,7 +85,8 @@ final class JwtAuthentication implements MiddlewareInterface
8585
"ignore" => null,
8686
"before" => null,
8787
"after" => null,
88-
"error" => null
88+
"error" => null,
89+
"responseFactory" => null,
8990
];
9091

9192
public function __construct(array $options = [])
@@ -139,7 +140,8 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
139140
$token = $this->fetchToken($request);
140141
$decoded = $this->decodeToken($token);
141142
} catch (RuntimeException | DomainException $exception) {
142-
$response = (new ResponseFactory)->createResponse(401);
143+
$factory = $this->options['responseFactory'] ?? new ResponseFactory;
144+
$response = $factory->createResponse(401);
143145
return $this->processError($response, [
144146
"message" => $exception->getMessage(),
145147
"uri" => (string)$request->getUri()
@@ -158,7 +160,6 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
158160

159161
/* Modify $request before calling next middleware. */
160162
if (is_callable($this->options["before"])) {
161-
$response = (new ResponseFactory)->createResponse(200);
162163
$beforeRequest = $this->options["before"]($request, $params);
163164
if ($beforeRequest instanceof ServerRequestInterface) {
164165
$request = $beforeRequest;
@@ -452,4 +453,12 @@ private function rules(array $rules): void
452453
$this->rules->push($callable);
453454
}
454455
}
456+
457+
/**
458+
* Set the response factory.
459+
*/
460+
private function responseFactory(ResponseFactoryInterface $factory = null): void
461+
{
462+
$this->options["responseFactory"] = $factory;
463+
}
455464
}

tests/JwtAuthenticationTest.php

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,18 @@
3333
namespace Tuupola\Middleware;
3434

3535
use Equip\Dispatch\MiddlewareCollection;
36+
use Exception;
3637
use PHPUnit\Framework\TestCase;
37-
use Psr\Http\Message\ServerRequestInterface;
38+
use Psr\Http\Message\ResponseFactoryInterface;
3839
use Psr\Http\Message\ResponseInterface;
40+
use Psr\Http\Message\ServerRequestInterface;
3941
use Tuupola\Http\Factory\ResponseFactory;
4042
use Tuupola\Http\Factory\ServerRequestFactory;
4143
use Tuupola\Http\Factory\StreamFactory;
4244
use Tuupola\Middleware\JwtAuthentication\RequestMethodRule;
4345
use Tuupola\Middleware\JwtAuthentication\RequestPathRule;
46+
use Zend\Diactoros\Response;
47+
use Zend\Diactoros\ResponseFactory as ZendResponseFactory;
4448

4549
class JwtAuthenticationTest extends TestCase
4650
{
@@ -863,6 +867,49 @@ public function testShouldCallErrorAndModifyBody()
863867
$this->assertTrue($dummy);
864868
}
865869

870+
public function testShouldUseCustomResponseFactory()
871+
{
872+
// custom response factory will accumulate status codes used in the createResponse call
873+
if(class_exists(ZendResponseFactory::class)) {
874+
$factory = new class extends ZendResponseFactory {
875+
public $used = [];
876+
public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface
877+
{
878+
$this->used[] = $code; // store the codes used
879+
return parent::createResponse($code, $reasonPhrase);
880+
}
881+
};
882+
} else {
883+
$factory = new class implements ResponseFactoryInterface {
884+
public $used = [];
885+
public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface
886+
{
887+
$this->used[] = $code; // store the codes used
888+
return (new Response)->withStatus($code, $reasonPhrase);
889+
}
890+
};
891+
}
892+
893+
$collection = new MiddlewareCollection([
894+
new JwtAuthentication([
895+
"secret" => "supersecretkeyyoushouldnotcommittogithub",
896+
"responseFactory" => $factory,
897+
])
898+
]);
899+
900+
$request = (new ServerRequestFactory)->createServerRequest("GET", "https://example.com/api");
901+
$response = $collection->dispatch($request, function () {
902+
// this callable is not used anyway due to auth error
903+
throw new Exception('not used');
904+
});
905+
906+
// assert correct response status code
907+
$this->assertEquals(401, $response->getStatusCode());
908+
909+
// assert that the custom response factory was used
910+
$this->assertSame([401], $factory->used);
911+
}
912+
866913
public function testShouldAllowUnauthenticatedHttp()
867914
{
868915

0 commit comments

Comments
 (0)