I followed the instructions to save token in container with callback function (https://github.com/tuupola/slim-jwt-auth):
$app = new \Slim\App();
$container = $app->getContainer();
$container["jwt"] = function ($container) {
return new StdClass;
};
$app->add(new \Slim\Middleware\JwtAuthentication([
"path" => ["/"],
"passthrough" => ["/version", "/auth"],
"secret" => "mysecret",
"callback" => function ($request, $response, $arguments) use ($container) {
$container["jwt"] = $arguments["decoded"];
},
"error" => function ($request, $response, $arguments) {
$data["status"] = "error";
$data["message"] = $arguments["message"];
return $response
->withHeader("Content-Type", "application/json")
->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
]));
No data is returned in response, it seems $this->jwt is empty.
$app->get("/user", 'getUsers');
function getUsers($req, $res, $args) {
$decode = $this->jwt;
print_r($decode);
}
Your route definition throws Using $this when not in object context error. To have access to $this you need to use a closure instead. See closure binding in the documentation.
$app->get("/user", function ($request, $response, $arguments) {
$decode = $this->jwt;
print_r($decode);
});
or
$getUsers = function ($request, $response, $arguments) use ($container) {
$decode = $this->jwt;
print_r($decode);
};
$app->get("/user", $getUsers);
With the either of code above you can access decoded token via $this. First example is preferred.
$ curl --include http://localhost:8081/user --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.mHEOMTUPhzNDAKheszd1A74EyLmKgy3PFdmKLg4ZNAE"
HTTP/1.1 200 OK
Host: localhost:8081
Connection: close
X-Powered-By: PHP/7.0.12
Content-Type: text/html; charset=UTF-8
Content-Length: 84
stdClass Object
(
[sub] => 1234567890
[name] => John Doe
[admin] => 1
)
The instruction you linked to states:
Callback is called only when authentication succeeds. It receives
decoded token in arguments. If callback returns boolean false
authentication is forced to be failed.
Do you meet this requirement when testing, i.e do you authenticate successfully? Also consider using var_dump($decode) instead of print_r($decode) when testing.
Related
I implemented ErrorHandler in my Slim Framework REST API:
$container['errorHandler'] = function ($c) {
return function (ServerRequestInterface $request, Response $response, $exception) use ($c) {
$data = [
'message' => $exception->getMessage()
];
return $c->get('response')->withStatus(500)
->withHeader('Content-Type', 'application/json')
->write(json_encode($data));
};
};
I try to create error:
public function test(ServerRequestInterface $request, Response $response){
$email = null;
$arr = [1,2];
$x = $arr[3]; //Undefined array key 3
}
I see the error in the Postman correctly (Status 500, {message: Undefined array key 3}, but in Developer tools in browser (Response tab) is only "Failed to load response data: No data found for resource with gived identifier".
In JS is this error:
{"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"http://localhost:8080/auth/login","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://localhost:8080/auth/login: 0 Unknown Error","error":{"isTrusted":true}}
When I send error response from test method:
public function test(ServerRequestInterface $request, Response $response){
return $response->withStatus(500)
->withHeader('Content-Type', 'application/json')
->write("ERROR");
}
in JS is correct exception object, and I see response in Developer tools:
{"headers":{"normalizedNames":{},"lazyUpdate":null},"status":500,"statusText":"Internal Server Error","url":"http://localhost:8080/auth/login","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://localhost:8080/auth/login: 500 Internal Server Error","error":"ERROR"}
what could be the problem? How to send error from errorHandler correctly?
Thanks for advices
The PSR-7 headers are immutable, but the HTTP body methods are not immutable.
To fix it try this:
$response = $response
->withStatus(500)
->withHeader('Content-Type', 'application/json');
$response->getBody()->write(json_encode($data)));
return $response;
i a, having a link which sends public to view timeline of a specific user by passing variable in route.
<a href="<?php echo $baseLocation ?>/bnb-details/<?php echo $row['username']?>" >View</a>
and my route is defined as:
$app->get('/bnb-details/{name}', function (Request $request, Response $response, $args) {
include_once('bnb-details.php');
return $response; });
how can i pass the {name} args in the bnb-details.php ??
any kind of help would be appriciated.
you can use like this :
you should pass parametere from args to variable
$app->get('/bnb-details/{name}', function (\Slim\Http\Request $request, \Slim\Http\Response $response, $args) {
$name = $args['name'];
include_once('bnb-details.php');
return $response;
});
then use
echo $name;
in bnb-details.php
I am using slim framework 3 . I am new to this framework. I am working on catching the errors and returning the custom JSON error and message.
I used this code to catch notFoundHandler error :
$container['notFoundHandler'] = function ($c) {
return function ($request, $response) use ($c) {
return $c['response']
->withStatus(404)
->withHeader('Content-Type', 'application/json')
->write('Page not found');
};
};
But I am able to catch the normal syntax error.
It is showing Warning: fwrite() expects parameter 2 to be string, array given in X-api\controllers\Products.php on line 42
Instead of this message, I want my custom error to handle syntax error reporting.
I used this also,
$container['phpErrorHandler'] = function ($c) {
return function ($request, $response, $exception) use ($c) {
//Format of exception to return
$data = [
'message' => "hello"
];
return $container->get('response')->withStatus($response->getStatus())
->withHeader('Content-Type', 'application/json')
->write(json_encode($data));
};
};
But not working for me.
The default error handler can also include detailed error diagnostic information. To enable this you need to set the displayErrorDetails setting to true:
$configuration = [
'settings' => [
'displayErrorDetails' => true,
],
];
$c = new \Slim\Container($configuration);
$app = new \Slim\App($c);
Note this is not appropriate for production applications, since it may reveal some details you would want not to reveal. You can find more in Slim docs.
EDIT
If you need to handle parseErrors, then you need to define phpErrorHandler in your container, just like you did define notFoundHandler.
$container['phpErrorHandler'] = function ($container) {
return function ($request, $response, $error) use ($container) {
return $container['response']
->withStatus(500)
->withHeader('Content-Type', 'text/html')
->write('Something went wrong!');
};
};
Note: this will work with PHP7+ only, because in older versions parseErrors cannot be catched.
I have used this short of code in my dependencies.php
$container['errorHandler'] = function ($c) {
return function ($request, $response) use ($c) {
$data = [
'message' => "Syntex error"
];
return $c['response']
->withStatus(200)
->withHeader('Content-Type', 'application/json')
->write(json_encode($data));
};
};
set_error_handler(function ($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting, so ignore it
return;
}
throw new \ErrorException($message, 0, $severity, $file, $line);
});
Now its working for me.
How do I test a GET request of a REST API with PHPUnit 4.1? I use the Slim PHP-Framework and could manage to test the response code but not the body or header.
This is what I have so far:
TestClass:
class AssetTest extends PHPUnit_Framework_TestCase
{
public function request($method, $path, $options = array())
{
// Capture STDOUT
ob_start();
// Prepare a mock environment
Environment::mock(array_merge(array(
'REQUEST_METHOD' => $method,
'PATH_INFO' => $path,
'SERVER_NAME' => 'slim-test.dev',
), $options));
$app = new \Slim\Slim();
$this->app = $app;
$this->request = $app->request();
$this->response = $app->response();
// Return STDOUT
return ob_get_clean();
}
public function get($path, $options = array()){
$this->request('GET', $path, $options);
}
public function testGetAssets(){
$this->get('/asset');
$this->assertEquals('200', $this->response->status());
}
}
If my JSON response of http://example.com/asset looks like this (Code 200):
[
{
"AssetID": "4b0be88b9e853",
"AssetStatusID": "1"
}
]
Everything is good. To get the body of response just call the
$response->getBody() and use json_decode to decode this response. To get the header call the $response->getHeaders().
In your case it will by $this->response->getBody(). So your test
method will be look like this
public function testGetAssets(){
$this->get('/asset');
$response = json_decode($this->response->getBody(), true); //response body
$headers = $this->response->getHeaders() //response headers
$this->assertEquals('200', $this->response->status());
}
This answer is respect to the latest version of guzzlehttp i.e. 6.0
I was trying to eliminate the logging in process to a website by reading the browser cookies (which I created by logging in using Firefox earlier). I exported it from Firefox using this Firefox addon. It gives a 200 OK response but returns the generic homepage instead of my custom 'logged in' home page. How do I make sure that cookie is passed to the server properly ?
#!/usr/bin/perl
use strict ;
use warnings;
use LWP::UserAgent;
use HTTP::Cookies::Netscape;
my #GHeader = (
'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.19) Gecko/2010040200 Ubuntu/8.04 (hardy) Firefox/3.0.19',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language' => 'en-us,en;q=0.5',
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
'Accept-Encoding' => 'gzip,deflate',
'Keep-Alive' => '300',
'Connection' => 'keep-alive'
);
my $cookie_jar = HTTP::Cookies::Netscape->new(
file => "cookies.txt",
);
my $Browser = LWP::UserAgent->new;
$Browser->cookie_jar( $cookie_jar );
my ($OutLine,$response)=();
my $URL = 'http://www.hanggliding.org/';
printf("Get [%s]\n",$URL);
$response = $Browser->get($URL,#GHeader);
if($response->is_success)
{
if($response->status_line ne "200 OK")
{
printf("%s\n", $response->status_line);
}
else
{
printf("%s\n", $response->status_line);
$OutLine =$response->decoded_content;
open(HTML,">out.html");printf HTML ("%s",$OutLine);close(HTML);
}
}
else
{
printf("Failed to get url [%s]\n", $response->status_line);
}
You can inject a handler to access or modify request/response data during processing.
Quoting LWP::UserAgent's docs:
Handlers are code that injected at various phases during the processing of requests. The following methods are provided to manage the active handlers:
$ua->add_handler( $phase => \&cb, %matchspec )
Add handler to be invoked in the given processing phase. For how to specify %matchspec see "Matching" in HTTP::Config.
...
request_send => sub { my($request, $ua, $h) = #_; ... }
This handler gets a chance of handling requests before they're sent to the protocol handlers. It should return an HTTP::Response object if it wishes to terminate the processing; otherwise it should return nothing.
From there, you can inject a handler which will analyze the request object, but otherwise do nothing:
use LWP::UserAgent;
use Data::Dumper;
sub dump_request {
my ($request, $ua, $h) = #_;
print Dumper($request);
return undef;
}
my $browser = LWP::UserAgent->new;
$browser->add_handler(
request_send => \&dump_request,
m_method => 'GET'
);
$browser->get('http://www.google.com');