-
Notifications
You must be signed in to change notification settings - Fork 0
Slim 3 Example
Andy Dyer edited this page Feb 18, 2020
·
8 revisions
composer require andrewdyer/jwt-auth firebase/php-jwt illuminate/database nesbot/carbon slim/slim:3.*
Update composer.json
and add autoload information.
{
// ...
+ "autoload": {
+ "psr-4": {
+ "App\\": "app"
+ }
+ }
}
Create a user model which extends Illuminate\Database\Eloquent\Model
and implements the Anddye\JwtAuth\Contracts\JwtSubject
interface.
<?php
namespace App\Models;
use Anddye\JwtAuth\Contracts\JwtSubject;
use Illuminate\Database\Eloquent\Model;
final class User extends Model implements JwtSubject
{
public function getJwtIdentifier(): int
{
return $this->id;
}
}
Create an auth provider which implements the Anddye\JwtAuth\Providers\AuthProviderInterface
interface. This will handle the user validation.
<?php
namespace App\Providers;
use Anddye\JwtAuth\Contracts\JwtSubject;
use Anddye\JwtAuth\Providers\AuthProviderInterface;
use App\Models\User;
final class AuthProvider implements AuthProviderInterface
{
public function byCredentials(string $username, string $password): ?JwtSubject
{
if (!$user = User::where('username', $username)->first()) {
return null;
}
if (!password_verify($password, $user->password)) {
return null;
}
return $user;
}
public function byId(int $id): ?JwtSubject
{
return User::find($id);
}
}
Create an jwt provider which implements the Anddye\JwtAuth\Providers\JwtProviderInterface
interface. This will handle encoding / decoding of the jwt token. The slim container is injected to get config properties off the settings array.
<?php
namespace App\Providers;
use Anddye\JwtAuth\Providers\JwtProviderInterface;
use Firebase\JWT\JWT;
final class JwtProvider implements JwtProviderInterface
{
protected $algorithm;
protected $secret;
public function __construct(string $algorithm, string $secret)
{
$this->algorithm = $algorithm;
$this->secret = $secret;
}
public function decode(string $token)
{
return JWT::decode($token, $this->secret, [$this->algorithm]);
}
public function encode(array $claims): string
{
return JWT::encode($claims, $this->secret, $this->algorithm);
}
}
<?php
namespace App\Controllers;
use Anddye\JwtAuth\JwtAuth;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class LoginController
{
protected $jwtAuth;
public function __construct(JwtAuth $jwtAuth)
{
$this->jwtAuth = $jwtAuth;
}
public function postAction(Request $request, Response $response): Response
{
$username = $request->getParam('username', '');
$password = $request->getParam('password', '');
if (!$token = $this->jwtAuth->attempt($username, $password)) {
return $response->withJson(['error' => '']);
}
return $response->withJson(['token' => $token]);
}
}
<?php
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class ActorController
{
public function getAction(Request $request, Response $response): Response
{
$actor = $request->getAttribute('actor');
return $response->withJson($actor);
}
}
<?php
namespace App\Middleware;
use Anddye\JwtAuth\JwtAuth;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class AuthenticateMiddleware
{
protected $jwtAuth;
public function __construct(JwtAuth $jwtAuth)
{
$this->jwtAuth = $jwtAuth;
}
public function __invoke(Request $request, Response $response, callable $next): Response
{
if (!$header = $this->getAuthorizationHeader($request)) {
return $response->withJson(['error' => 'Authorization header is missing!'], 401);
}
if (!$token = $this->extractToken($header)) {
return $response->withStatus(401);
}
if (!$actor = $this->jwtAuth->authenticate($token)->getActor()) {
return $response->withStatus(401);
}
$request = $request->withAttribute('actor', $actor);
return $next($request, $response);
}
protected function extractToken($header): ?string
{
if (preg_match('/Bearer\s(\S+)/', $header, $matches)) {
return $matches[1];
}
return null;
}
protected function getAuthorizationHeader(Request $request): ?string
{
if ($header = $request->getHeader('Authorization')) {
list($header) = $header;
return $header;
}
return null;
}
}
<?php
use Anddye\JwtAuth\ClaimsFactory;
use Anddye\JwtAuth\JwtAuth;
use App\Controllers\ActorController;
use App\Controllers\LoginController;
use App\Middleware\AuthenticateMiddleware;
use App\Providers\AuthProvider;
use App\Providers\JwtProvider;
use Carbon\Carbon;
use Illuminate\Database\Capsule\Manager as Capsule;
use Slim\App;
require __DIR__ . '/../vendor/autoload.php';
$app = new App([
'settings' => [
'displayErrorDetails' => true,
'database' => [
'driver' => 'mysql',
'host' => '127.0.0.1',
'port' => '3306',
'database' => '',
'username' => '',
'password' => '',
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
],
'jwt' => [
'algorithm' => 'HS256',
'issuer' => 'https://github.com/andrewdyer/jwt-auth',
'jwt_id' => '60ad17YE73',
'secret' => 'supersecretkeynottobecommitedtogithub',
],
],
]);
$container = $app->getContainer();
$container[Capsule::class] = function ($container) {
$capsule = new Capsule();
$capsule->addConnection($container->get('settings')['database']);
$capsule->setAsGlobal();
return $capsule;
};
$container[Capsule::class]->bootEloquent();
$container[JwtAuth::class] = function ($container) {
$settings = $container->get('settings')['jwt'];
$authProvider = new AuthProvider();
$jwtProvider = new JwtProvider($settings['algorithm'], $settings['secret']);
$claimsFactory = ClaimsFactory::build([
'exp' => Carbon::now()->addMinute(5)->getTimestamp(),
'iat' => Carbon::now()->getTimestamp(),
'iss' => $settings['issuer'],
'jti' => $settings['jwt_id'],
'nbf' => Carbon::now()->getTimestamp(),
]);
return new JwtAuth($authProvider, $jwtProvider, $claimsFactory);
};
$container[ActorController::class] = function () {
return new ActorController();
};
$container[LoginController::class] = function ($container) {
return new LoginController(
$container->get(JwtAuth::class)
);
};
$container[AuthenticateMiddleware::class] = function ($container) {
return new AuthenticateMiddleware(
$container->get(JwtAuth::class)
);
};
$app->get('/auth/me', ActorController::class . ':getAction')->add($container[AuthenticateMiddleware::class]);
$app->post('/auth/login', LoginController::class . ':postAction');
$app->run();