mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 09:39:57 +00:00
Revise session handling to prepare API authentication via token
This commit is contained in:
parent
0c85342404
commit
eae5b8bad9
22
app.php
22
app.php
@ -3,16 +3,13 @@
|
|||||||
use \Psr\Http\Message\ServerRequestInterface as Request;
|
use \Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use \Psr\Http\Message\ResponseInterface as Response;
|
use \Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
|
||||||
use \Grocy\Middleware\SessionAuthMiddleware;
|
|
||||||
use \Grocy\Helpers\UrlManager;
|
use \Grocy\Helpers\UrlManager;
|
||||||
use \Grocy\Services\ApplicationService;
|
use \Grocy\Controllers\LoginController;
|
||||||
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
require_once __DIR__ . '/data/config.php';
|
require_once __DIR__ . '/data/config.php';
|
||||||
|
|
||||||
// Setup base application
|
// Setup base application
|
||||||
if (PHP_SAPI !== 'cli')
|
|
||||||
{
|
|
||||||
$appContainer = new \Slim\Container([
|
$appContainer = new \Slim\Container([
|
||||||
'settings' => [
|
'settings' => [
|
||||||
'displayErrorDetails' => true,
|
'displayErrorDetails' => true,
|
||||||
@ -22,25 +19,20 @@ if (PHP_SAPI !== 'cli')
|
|||||||
{
|
{
|
||||||
return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache');
|
return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache');
|
||||||
},
|
},
|
||||||
|
'LoginControllerInstance' => function($container)
|
||||||
|
{
|
||||||
|
return new LoginController($container, 'grocy_session');
|
||||||
|
},
|
||||||
'UrlManager' => function($container)
|
'UrlManager' => function($container)
|
||||||
{
|
{
|
||||||
return new UrlManager(BASE_URL);
|
return new UrlManager(BASE_URL);
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$app = new \Slim\App($appContainer);
|
$app = new \Slim\App($appContainer);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$app = new \Slim\App();
|
|
||||||
$app->add(\pavlakis\cli\CliRequest::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add session handling if this is not a demo installation
|
if (PHP_SAPI === 'cli')
|
||||||
$applicationService = new ApplicationService();
|
|
||||||
if (!$applicationService->IsDemoInstallation())
|
|
||||||
{
|
{
|
||||||
$app->add(SessionAuthMiddleware::class);
|
$app->add(\pavlakis\cli\CliRequest::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/routes.php';
|
require_once __DIR__ . '/routes.php';
|
||||||
|
@ -9,13 +9,15 @@ use \Grocy\Services\DemoDataGeneratorService;
|
|||||||
|
|
||||||
class LoginController extends BaseController
|
class LoginController extends BaseController
|
||||||
{
|
{
|
||||||
public function __construct(\Slim\Container $container)
|
public function __construct(\Slim\Container $container, string $sessionCookieName)
|
||||||
{
|
{
|
||||||
parent::__construct($container);
|
parent::__construct($container);
|
||||||
$this->SessionService = new SessionService();
|
$this->SessionService = new SessionService();
|
||||||
|
$this->SessionCookieName = $sessionCookieName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $SessionService;
|
protected $SessionService;
|
||||||
|
protected $SessionCookieName;
|
||||||
|
|
||||||
public function ProcessLogin(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
public function ProcessLogin(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||||
{
|
{
|
||||||
@ -25,7 +27,7 @@ class LoginController extends BaseController
|
|||||||
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
|
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
|
||||||
{
|
{
|
||||||
$sessionKey = $this->SessionService->CreateSession();
|
$sessionKey = $this->SessionService->CreateSession();
|
||||||
setcookie('grocy_session', $sessionKey, time() + 31536000); // Cookie expires in 1 year, but session validity is up to SessionService
|
setcookie($this->SessionCookieName, $sessionKey, time() + 31536000); // Cookie expires in 1 year, but session validity is up to SessionService
|
||||||
|
|
||||||
return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/'));
|
return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/'));
|
||||||
}
|
}
|
||||||
@ -47,7 +49,7 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
public function Logout(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
public function Logout(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args)
|
||||||
{
|
{
|
||||||
$this->SessionService->RemoveSession($_COOKIE['grocy_session']);
|
$this->SessionService->RemoveSession($_COOKIE[$this->SessionCookieName]);
|
||||||
return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/'));
|
return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,4 +68,9 @@ class LoginController extends BaseController
|
|||||||
|
|
||||||
return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/stockoverview'));
|
return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/stockoverview'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function GetSessionCookieName()
|
||||||
|
{
|
||||||
|
return $this->SessionCookieName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,3 +61,14 @@ function GetClassConstants($className)
|
|||||||
$r = new ReflectionClass($className);
|
$r = new ReflectionClass($className);
|
||||||
return $r->getConstants();
|
return $r->getConstants();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RandomString($length, $allowedChars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||||
|
{
|
||||||
|
$randomString = '';
|
||||||
|
for ($i = 0; $i < $length; $i++)
|
||||||
|
{
|
||||||
|
$randomString .= $allowedChars[rand(0, strlen($allowedChars) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $randomString;
|
||||||
|
}
|
||||||
|
@ -2,11 +2,16 @@
|
|||||||
|
|
||||||
namespace Grocy\Middleware;
|
namespace Grocy\Middleware;
|
||||||
|
|
||||||
|
use \Grocy\Services\ApplicationService;
|
||||||
|
|
||||||
class BaseMiddleware
|
class BaseMiddleware
|
||||||
{
|
{
|
||||||
public function __construct(\Slim\Container $container) {
|
public function __construct(\Slim\Container $container)
|
||||||
|
{
|
||||||
$this->AppContainer = $container;
|
$this->AppContainer = $container;
|
||||||
|
$this->ApplicationService = new ApplicationService();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected $AppContainer;
|
protected $AppContainer;
|
||||||
|
protected $ApplicationService;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class CliMiddleware extends BaseMiddleware
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$response = $next($request, $response, $next);
|
$response = $next($request, $response);
|
||||||
return $response->withHeader('Content-Type', 'text/plain');
|
return $response->withHeader('Content-Type', 'text/plain');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ class JsonMiddleware extends BaseMiddleware
|
|||||||
{
|
{
|
||||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
||||||
{
|
{
|
||||||
$response = $next($request, $response, $next);
|
$response = $next($request, $response);
|
||||||
return $response->withHeader('Content-Type', 'application/json');
|
return $response->withHeader('Content-Type', 'application/json');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,27 @@ use \Grocy\Services\SessionService;
|
|||||||
|
|
||||||
class SessionAuthMiddleware extends BaseMiddleware
|
class SessionAuthMiddleware extends BaseMiddleware
|
||||||
{
|
{
|
||||||
|
public function __construct(\Slim\Container $container, string $sessionCookieName)
|
||||||
|
{
|
||||||
|
parent::__construct($container);
|
||||||
|
$this->SessionCookieName = $sessionCookieName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected $SessionCookieName;
|
||||||
|
|
||||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
||||||
{
|
{
|
||||||
$route = $request->getAttribute('route');
|
$route = $request->getAttribute('route');
|
||||||
$routeName = $route->getName();
|
$routeName = $route->getName();
|
||||||
|
|
||||||
if ($routeName === 'root')
|
if ($routeName === 'root' || $this->ApplicationService->IsDemoInstallation())
|
||||||
{
|
{
|
||||||
$response = $next($request, $response);
|
$response = $next($request, $response);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$sessionService = new SessionService();
|
$sessionService = new SessionService();
|
||||||
if ((!isset($_COOKIE['grocy_session']) || !$sessionService->IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
|
if ((!isset($_COOKIE[$this->SessionCookieName]) || !$sessionService->IsValidSession($_COOKIE[$this->SessionCookieName])) && $routeName !== 'login')
|
||||||
{
|
{
|
||||||
$response = $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/login'));
|
$response = $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/login'));
|
||||||
}
|
}
|
||||||
|
55
routes.php
55
routes.php
@ -2,48 +2,51 @@
|
|||||||
|
|
||||||
use \Grocy\Middleware\JsonMiddleware;
|
use \Grocy\Middleware\JsonMiddleware;
|
||||||
use \Grocy\Middleware\CliMiddleware;
|
use \Grocy\Middleware\CliMiddleware;
|
||||||
|
use \Grocy\Middleware\SessionAuthMiddleware;
|
||||||
|
|
||||||
|
$app->group('', function()
|
||||||
|
{
|
||||||
// Base route
|
// Base route
|
||||||
$app->get('/', 'Grocy\Controllers\LoginController:Root')->setName('root');
|
$this->get('/', 'LoginControllerInstance:Root')->setName('root');
|
||||||
|
|
||||||
// Login routes
|
// Login routes
|
||||||
$app->get('/login', 'Grocy\Controllers\LoginController:LoginPage')->setName('login');
|
$this->get('/login', 'LoginControllerInstance:LoginPage')->setName('login');
|
||||||
$app->post('/login', 'Grocy\Controllers\LoginController:ProcessLogin')->setName('login');
|
$this->post('/login', 'LoginControllerInstance:ProcessLogin')->setName('login');
|
||||||
$app->get('/logout', 'Grocy\Controllers\LoginController:Logout');
|
$this->get('/logout', 'LoginControllerInstance:Logout');
|
||||||
|
|
||||||
// Stock routes
|
// Stock routes
|
||||||
$app->get('/stockoverview', 'Grocy\Controllers\StockController:Overview');
|
$this->get('/stockoverview', 'Grocy\Controllers\StockController:Overview');
|
||||||
$app->get('/purchase', 'Grocy\Controllers\StockController:Purchase');
|
$this->get('/purchase', 'Grocy\Controllers\StockController:Purchase');
|
||||||
$app->get('/consume', 'Grocy\Controllers\StockController:Consume');
|
$this->get('/consume', 'Grocy\Controllers\StockController:Consume');
|
||||||
$app->get('/inventory', 'Grocy\Controllers\StockController:Inventory');
|
$this->get('/inventory', 'Grocy\Controllers\StockController:Inventory');
|
||||||
|
|
||||||
$app->get('/products', 'Grocy\Controllers\StockController:ProductsList');
|
$this->get('/products', 'Grocy\Controllers\StockController:ProductsList');
|
||||||
$app->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm');
|
$this->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm');
|
||||||
|
|
||||||
$app->get('/locations', 'Grocy\Controllers\StockController:LocationsList');
|
$this->get('/locations', 'Grocy\Controllers\StockController:LocationsList');
|
||||||
$app->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm');
|
$this->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm');
|
||||||
|
|
||||||
$app->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList');
|
$this->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList');
|
||||||
$app->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm');
|
$this->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm');
|
||||||
|
|
||||||
$app->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList');
|
$this->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList');
|
||||||
$app->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm');
|
$this->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm');
|
||||||
|
|
||||||
|
|
||||||
// Habit routes
|
// Habit routes
|
||||||
$app->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview');
|
$this->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview');
|
||||||
$app->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution');
|
$this->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution');
|
||||||
|
|
||||||
$app->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList');
|
$this->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList');
|
||||||
$app->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm');
|
$this->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm');
|
||||||
|
|
||||||
// Batterry routes
|
// Batterry routes
|
||||||
$app->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview');
|
$this->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview');
|
||||||
$app->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle');
|
$this->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle');
|
||||||
|
|
||||||
$app->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList');
|
|
||||||
$app->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm');
|
|
||||||
|
|
||||||
|
$this->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList');
|
||||||
|
$this->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm');
|
||||||
|
})->add(new SessionAuthMiddleware($appContainer, $appContainer->LoginControllerInstance->GetSessionCookieName()));
|
||||||
|
|
||||||
$app->group('/api', function()
|
$app->group('/api', function()
|
||||||
{
|
{
|
||||||
@ -65,7 +68,7 @@ $app->group('/api', function()
|
|||||||
|
|
||||||
$this->get('/batteries/track-charge-cycle/{batteryId}', 'Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
|
$this->get('/batteries/track-charge-cycle/{batteryId}', 'Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
|
||||||
$this->get('/batteries/get-battery-details/{batteryId}', 'Grocy\Controllers\BatteriesApiController:BatteryDetails');
|
$this->get('/batteries/get-battery-details/{batteryId}', 'Grocy\Controllers\BatteriesApiController:BatteryDetails');
|
||||||
})->add(JsonMiddleware::class);
|
})->add(new SessionAuthMiddleware($appContainer, $appContainer->LoginControllerInstance->GetSessionCookieName()))->add(JsonMiddleware::class);
|
||||||
|
|
||||||
$app->group('/cli', function()
|
$app->group('/cli', function()
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ class SessionService extends BaseService
|
|||||||
*/
|
*/
|
||||||
public function CreateSession()
|
public function CreateSession()
|
||||||
{
|
{
|
||||||
$newSessionKey = uniqid() . uniqid() . uniqid();
|
$newSessionKey = $this->GenerateSessionKey();
|
||||||
|
|
||||||
$sessionRow = $this->Database->sessions()->createRow(array(
|
$sessionRow = $this->Database->sessions()->createRow(array(
|
||||||
'session_key' => $newSessionKey,
|
'session_key' => $newSessionKey,
|
||||||
@ -39,4 +39,9 @@ class SessionService extends BaseService
|
|||||||
{
|
{
|
||||||
$this->Database->sessions()->where('session_key', $sessionKey)->delete();
|
$this->Database->sessions()->where('session_key', $sessionKey)->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function GenerateSessionKey()
|
||||||
|
{
|
||||||
|
return RandomString(50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user