What's wrong with my code? I can't pass variable from my Auth middleware to controller. In controller, the attribute "null".
Index:
$c = new \Slim\Container($configuration);
$api = new \Slim\App($c);
$api->group('/', function () use ($api) {
$this->post('login', '\AuthController:login');
...
$this->post('getIngredientsCategories', '\IngredientsController:getIngredientsCategories');
})->add(new ApiAuthenticateController());
$api->run();
Middleware (ApiAuthenticateController)
use \Firebase\JWT\JWT;
class ApiAuthenticateController
{
public function __invoke($request, $response, $next)
{
$jwtDecoded = null;
$req = $request->getUri()->getPath();
$_req = RequestValidatorController::isRequestEnabled($req);
if ($_req !== false) {
if ($_req['login_required']) {
$jwt = filter_var($request->getHeaderLine('AUTHORIZATION'), FILTER_SANITIZE_STRING);
$jwt = explode(" ", $jwt)[1];
try {
$jwtDecoded = JWT::decode($jwt, JWT_SECRET, array('HS256'));
} catch (\Exception $e) {
return $this->deny_access($response);
}
}
$request = $request->withAttribute('foo', $jwtDecoded);
//HERE - attribute "foo" in $request exists - checked by var_dump()..
$response = $next($request, $response);
$response = $response->withHeader('Content-type', 'application/json');
return $response;
} else {
return $this->deny_access($response);
}
}
IngredientsController
class IngredientsController extends Controller
{
private $_ingredients;
public function __construct(\Interop\Container\ContainerInterface $container)
{
parent::__construct($container);
}
}
Controller
class Controller
{
private $request;
private $response;
protected $data;
protected $method;
protected $user;
public function __construct(Interop\Container\ContainerInterface $container)
{
$this->request = $container->get('request');
$this->response = $container->get('response');
$this->data = (object)Tools::stripInput($this->request->getParsedBody());
$this->method = $this->request->getUri()->getPath();
$this->user = $this->request->getAttribute('foo');
var_dump($this->user);
// returns NULL. if $this->request->getAttributes()... returns empty
}
}
Please note, that code is "cleaned" for this post and for better readability, some functions and conditions where deleted. Code is working - sorry for possible typos.
the problem is coming from here
in the middleware ApiAuthenticateController, you should change the code like this
$request = $request->withAttribute('foo', $jwtDecoded);
// you should return the $next here not to do anything else
return $next($request, $response);
and in your IngredientsController:getIngredientsCategories part of code you should return the
function getIngredientsCategories ($request, $response, $args){
//do your job...
$response = $response->withHeader('Content-type', 'application/json');
return $response;
}
and finally, in the constructor, you have don't have the actual $request after the middleware I think so you would have the $this->request->getAttributes() inside your getIngredientsCategories function
Hope it helps.
Related
Heres the code for the route:
<?php
use app\controllers\Home;
use app\core\App;
$app = new App();
$app->router->get('/', function(){
echo "hello there";
});
$app->router->get('user/', 'user');
$app->router->get('/contact', [Home::class,'contacts']);
$app->router->post('/contact', function(){
echo "handlecontact";
});
$app->run();
Heres the code for the router core class:
<?php
namespace app\core;
class router{
public Request $request;
public Response $response;
protected array $routes = [];
public function __construct(Request $request,Response $response)
{
$this->request = $request;
$this->response = $response;
}
public function get($path, $callback){
$this->routes['get'][$path] = $callback;
}
public function post($path, $callback){
$this->routes['post'][$path] = $callback;
}
public function resolve(){
$path = $this->request->getpath();
$method = $this->request->getmethod();
$callback = $this->routes[$method][$path] ?? false;
if($callback == false){
$this->response->setstatuscode(404);
return "not found";
}
if(is_array($callback)){
$callback[0] = new $callback[0]();
}
return call_user_func($callback,$this->request);
}
I want to be able to declare a route and pass a parameter to it. If i do it so like that it tells me route not found.
Like i want to be able to write the route like this:
$app->router->get('/contact/{id}', function(){
echo $id; // to echo it out like this from the controller
});
Can someone be of good help or also add something to the idea. Thanks in advance
I am using a middleware to redirect to login page if session is not set.
$app->get('/dashboard', function (Request $request, Response $response, $args) {
include_once('employee-portal/dashboard.php');
return $response;})->add(new AuthMiddleware('counter', true, $app->getContainer()));
and my middleware:
class AuthMiddleware implements MiddlewareInterface{
private $min_role = 'counter';
private $redirect = true;
private $container = null;
public function __construct($role_required, $login_redirect, $container)
{
$this->min_role = $role_required;
$this->redirect = $login_redirect;
$this->container = $container;
}
public function __invoke($request, $response, $next)
{
if ($this->userIsAuthorised()) {
return $next($request, $response);
} else {
if ($this->redirect) {
/**
* #var \Slim\Router router`
*/
return $response->withRedirect(Details::getBaseUrl() . '/login' . '?ref=' . $request->getUri());
}
return $response->withStatus(401)->write("Sorry boss you are not authorised to see my secret");
}
}
private function userIsAuthorised()
{
if ($this->min_role == 'counter') {
return true;
} else if (SessionManager::isLoggedIn()) {
if ($_SESSION['user_type']=='counter') {
return true;
}
}
return false;
} }
but this doesn't works.
i can even see the dashboard page without login. and even after login i cannot access the $_SESSION['user_type'] session variable.
any help would be appriciated. thanks in advance.
You are passing 'counter' into your AuthMiddleware constructor, causing it to always return true in the first if() statement of userIsAuthorised() method.
if ($this->min_role == 'counter')
will always be true because you set $this->min = 'counter' in your constructor. Try rewriting the new AuthMiddleware() and constructor so that you just pass in the container. Before calling the new AuthMiddleware() you can do the following:
$container['min_role'] = 'counter' if you need it elsewhere in your app.
I wish to check if the cookie is set, when doing the bottom getUsername(). Can anyone help me with a quick fix for this? I've tried for hours without luck.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cookie;
class CookieController extends Controller
{
public function setCookie(\stdClass $request)
{
$minutes = 60;
$response = new Response(view('panel.panel'));
$response->withCookie(cookie('userInfo', $request, $minutes));
return $response;
}
public function getCookie(){
$val = cookie::get('userInfo');
return $val;
}
public function getUsername(){
$cookie = cookie::get('userInfo');
return $cookie->message->username;
}
public function getShopID(){
$cookie = cookie::get('ShopID');
return $cookie->message->shopID;
}
}
?>
You could use isset or compare with null
public function getUsername(){
$cookie = cookie::get('userInfo');
if ($cookie !== null) {
// do something like set cookie
// return username
}
}
Try using the method hasCookie():
public function getUsername(Request $request)
{
if ($request->hasCookie('userInfo')) {
$cookie = $request->cookie('userInfo');
return $cookie->message->username;
}
}
I'm using Guzzle's asynchronous request and have them implemented in a service that I would like to test now.
My method looks like this (pseudo, so if it's not 100% valid, please excuse)
public function getPlayer(string $uiid, array &$player = [])
{
$options['query'] = ['id' => $uiid];
$promise = $this->requestAsync('GET', $this->endpoint, $options);
$promise->then(function (ResponseInterface $response) use (&$player) {
$player = $response->getBody()->getContents();
});
return $players;
}
Now I want to test it, but I don't really know how to mock the callable, because I'm always getting the error
1) tzfrs\PlayerBundle\Tests\Api\Player\PlayerServiceTest::testGetPlayer
Prophecy\Exception\InvalidArgumentException: Expected callable or instance of PromiseInterface, but got object.
This is how I have it implemented currently
/** #var ObjectProphecy|PromiseInterface $response */
$promise = $this->prophesize(PromiseInterface::class);
$promise->then()->will($this->returnCallback(function (ResponseInterface $response) use (&$player){}));
Didn't work. And this
$this->returnCallback(function (ResponseInterface $response) use (&$player){})
didn't work either. Same error. And when simply trying a dummy callback
$promise->then(function(){});
I get the error Error: Call to a member function then() on string, even after ->reveal()ing the promise first. Any ideas?
I had another idea.
Make a dependency that will make what you make now in requestAsync();
And then create it's mock that will return another mock of promise.
class PromiseMock
{
private $response;
public function __construct(ResponseInterface $response)
{
$this->response = $response;
}
public function then($callable)
{
$callable($this->response);
}
}
test looks like
public function testGetPlayer()
{
$response = new Response(200, [], "Your test response");
$promiseMock = new PromiseMock($response);
$mockDependency = $this->getMockBuilder('YourDependencyClass')
->getMock()
->expects("requestAsync")->willReturn($promiseMock);
$service = new YouServiceClass($mockDependency);
$service->getPlayer("76245914-d56d-4bac-8419-9e409f43e777");
}
And in your class changes only
$promise = $this->someNameService->requestAsync('GET', $this->endpoint, $options);
I would inject a processor to your class and call it's callable. Check it out, the rest is quite obvious:
public function __construct(Processor $processor) {
$this->processor = $processor;
}
public function getPlayer(string $uiid, array &$player = [])
{
$options['query'] = ['id' => $uiid];
$promise = $this->requestAsync('GET', $this->endpoint, $options);
$promise->then([$this->processor, "processResponse"]);
$player = $this->processor->getPlayer();
return $players;
}
And processor:
class Processor {
private $player;
public function processResponse (ResponseInterface $response) {
$this->player = $response->getBody()->getContents();
}
public function getPlayer() { return $this->player;}
}
I've been handed a PHP class, and I'm not interested in fully restructuring it. (it works!)
But I'd like to add a slight modification inside a few methods.
Here is one of the many methods inside the class:
<?php
class SomeFunClass {
public function getAccountInfo()
{
$request = $this->prepareRequest('get_account_info');
$response = $this->execute($request);
return $response;
}
}
?>
The return $response is a string value.
I've come to a point that I need to return the $request string, which happens to be a json string.
The prepareRequest() method always returns a json string, which is then passed to the exec() method, which simply sends the data via cURL to a domain.
I'd like to extract the $request string (when I call the getAccountInfo() method), for later review.
Here's what I'm doing now:
<?php
$api = new SomeFunClass();
$curlresponse = $api->getAccountInfo();
?>
Obviously, the example immediately above only gives me back what the cURL response would be.
Would be nice to call a method that lets me see what the $request looks like.
I'm open to suggestions.
Just return an array with the request and the response:
<?php
class SomeFunClass {
public function getAccountInfo()
{
$request = $this->prepareRequest('get_account_info');
$response = $this->execute($request);
return array('request' => $request, 'response' => $response);
}
}
?>
You can modify those methods to store the last request into an attribute of the current class :
<?php
class SomeFunClass {
$last_request;
...
public function getAccountInfo()
{
$request = $this->prepareRequest('get_account_info');
$last_request = request;
$response = $this->execute($request);
return $response;
}
public function getLastRequest()
{
return $this -> last_request;
}
}
?>
Or, better, if prepareRequest is a method of yours, then just modify this one to store the last request.
You can do something like this:
<?php
class SomeFunClass {
public $request;
public $response;
public function getAccountInfo()
{
$this->request = $this->prepareRequest('get_account_info');
$this->response = $this->execute($this->request);
return $this->response;
}
}
?>
Now, you can do something like this:
<?php
$api = new SomeFunClass();
$curlresponse = $api->getAccountInfo();
$request = $api->request;
?>
Ideally, you can do implement your class like this to take actual advantage of OOP (so that these instance variables request and response are auto-set for all your methods):
<?php
class SomeFunClass {
public $request;
public $response;
public function getAccountInfo()
{
$this->prepareRequest('get_account_info');
return $this->execute();
}
public function anotherMethod()
{
$this->prepareRequest('another_method', 'some', 'args');
return $this->execute();
}
public function prepareRequest()
{
$args = func_get_args(); // contains your arguments
$method = array_shift($args); // contains your method name
...
...
$this->request = $return // value returned by this method
}
public function execute()
{
$request = $this->request;
...
...
$this->response = $return // value returned by this method
}
}
?>
You could also do this:
<?php
class SomeFunClass {
public function reviewRequest($request)
{
return $this->prepareRequest($request);
}
}
And then:
<?php
$api = new SomeFunClass();
$request = $api->reviewRequest('get_account_info');