I have the same problem again.
Old post here
I have a angular app and SlimFramework for api connect.
Local it works fine but when i publish to my Website come the error that my Header no set.
But the info on the API testing tool says it's allowed from * IP.
Can someone help me?
Here a valid token: Basic TyOSZcfBwMC6DR9kbAWeMnPmhF4ohZu2n9LccQEyt6uXNt8PTT
Thx
$app = new \Slim\App(["settings" => $config]);
$container = $app->getContainer();
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE, PUT');
});
$container['logger'] = function($c) {
$logger = new \Monolog\Logger('my_logger');
$file_handler = new \Monolog\Handler\StreamHandler("../../logs/app.log");
$logger->pushHandler($file_handler);
return $logger;
};
$app->get('/token', function ($request, $response){
$db = new DbOperation();
if (!$request->hasHeader('Authorization')) {
return $response->withJson([
"success"=> false,
"message" => "Header not set.",
"textcode"=> "MSG2"
], 401);
}
$token = $request->getHeader('Authorization');
if($db->checkToken($token[0])){
$user = $db->userInfo($token[0]);
if($db->checkActivate($user['auth_user'])){
if($db->checkExpired($user['auth_user'])){
return $response->withJson([
"success"=> false,
"message" => "The validity of the login has expired. If you have any questions, please contact the administrator..",
"textcode"=> "MSG6"
], 401);
} else {
return $response->withJson(["success"=> true], 200);
}
} else {
return $response->withJson([
"success"=> false,
"message" => "This account has not yet been activated.",
"textcode"=> "MSG8"
], 401);
}
} else {
return $response->withJson([
"success"=> false,
"message"=>'Invalid token',
"textcode"=> "MSG1"
], 403);
}
});
Your basic auth credentials do not decode into anything meaningful. PHP tends to silently ignore Authorization headers which it thinks are malformed. Try with something like Basic dGVzdDp0ZXN0 which decodes into test:test.
Workaround for this has however been added to Slim starting from version 3.5.0. Upgrading your Slim installation might also help.
Related
I would like to make a get request from my Ionic app to an API build with the Slim Framework.
This is the code of the API:
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
?>
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Tuupola\Middleware\HttpBasicAuthentication;
require 'vendor/autoload.php';
$jwt_secret = '**************';
$app = new Slim\App;
$app->add(new Tuupola\Middleware\JwtAuthentication([
"path" => "/api",
"attribute" => "jwt",
"secret" => $jwt_secret, "error" => function ($response, $arguments) {
$data["status"] = "error";
$data["message"] = $arguments["message"];
return $response
->withHeader("Content-Type", "application/json")
->withHeader("Access-Control-Allow-Origin", "*")
->getBody()->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
}
]));
$app->get('/api/hello', function (Request $request, Response $response, array $args)
{
$decoded = $request->getAttribute("jwt");
$response->getBody()->write(json_encode(array("status"=> "200", "message" => "HELLO ".$decoded['uid'] ." - " . $decoded['cus'])));
return $response;
});
$app->get('/', function (Request $request, Response $response, array $args) {
$response->getBody()->write(json_encode(array("status"=> "200", "message" => "Welcome to the API")));
return $response;
});
$app->run();
?>
When I'm testing with postman the API works fine. But when I'm trying to call it with the HTTPClient in Ionic, it doesn't work. This is my Ionic Code:
import { Component } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
constructor(private http: HttpClient)
{
}
sendRequest()
{
this.http.get('http://localhost/slim3',).subscribe((data)=>console.log(data));
}
}
The Error message is the following:
:8100/home:1 Access to XMLHttpRequest at 'http://localhost/slim3' from origin 'http://localhost:8100' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
core.js:6014 ERROR HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: "Unknown Error", url: "http://localhost/slim3", ok: false, …}
How can I fix it? Thanks!
You must enable CORS(What is CORS?) in Slim Framework. Check http://www.slimframework.com/docs/v3/cookbook/enable-cors.html
Add this before $app->run(); (replacing http://mysite by your url, including port)
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
});
I'm using V1 of https://github.com/tymondesigns/jwt-auth
I need to create an expired token, to test the TokenExpiredException in my code:
public function handle($request, Closure $next)
{
try {
JWTAuth::parseToken()->authenticate();
} catch (Exception $e) {
if ($e instanceof TokenInvalidException) {
return response()->json(['status' => 'Token is Invalid'], 401);
} elseif ($e instanceof TokenExpiredException) {
return response()->json(['status' => 'Token is Expired'], 401);
} else {
return response()->json(['status' => 'Authorization Token not found'], 401);
}
}
return $next($request);
}
I cannot do it:
public function setUp(): void
{
parent::setUp();
$password = '123456';
$user = new User([
'email' => 'info#example.com',
'password' => Hash::make($password),
]);
$user->save();
}
public function testExpiredToken()
{
$user = User::first();
$token = JWTAuth::fromUser($user, ['exp'=> 123456]);
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$token,
])->get(Route('test_data_read_closed'));
$response->assertStatus(401);
}
But I get 200 from my test (token accepted, I got answer from my route) and not 401.
How can I create an expired token? Thank you
I spent hours trying to figure out why it was still responding with a 200 success code when an expired JWT is sent (for testing purposes). It turns out that the JWT package caches the claims in the \Tymon\JWTAuth\Factory instance. To fix it, you just have to clear the claims after the JWT is generated and before it's sent to a controller:
\Tymon\JWTAuth\Facades\JWTAuth::getPayloadFactory()->emptyClaims();
Otherwise, it thinks it's the same request and will re-use already built \Tymon\JWTAuth\Claims\Claim instances to decode another JWT. I will see about creating an issue on GitHub.
I have made PHP Slim server. Authentication for it and CSRF.
I want to use it as a REST Server.
I have a created an App using IonicFramework which uses Angular.
I want to authenticate myself with this code
let hheaders:Headers=new Headers();
hheaders.append('Access-Control-Allow-Origin' , '*');
hheaders.append('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
hheaders.append('Accept','application/json');
let options = new RequestOptions({ headers:hheaders});
let data = new FormData();
data.append("email", this.myForm.email);
data.append("password", this.myForm.password);
data.append("csrf_name", this.myForm.csrf_name);
data.append("csrf_value", this.myForm.csrf_value);
return this.http.post('http://10.1.3.101:8088/public/auth/signinservice',data,this.options)
.map(res => res.json())
.toPromise();
But I always get Failed CSRF check! I do not know what is the problem. At this point the Slim Server is basic. It is very simple and similar to this Github project with new methods in AuthController.php
like
public function getSignInService($request, $response){
$nameKey = $this->csrf->getTokenNameKey();
$valueKey = $this->csrf->getTokenValueKey();
$name = $request->getAttribute($nameKey);
$value = $request->getAttribute($valueKey);
$tokenArray = [
$nameKey => $name,
$valueKey => $value
];
return $response->write(json_encode($tokenArray));
}
and
public function postSignInService($request, $response, $args){
$auth = $this->auth->attempt(
$request->getParam('email'),
$request->getParam('password')
);
if(!$auth){
$data = array('status' => 'error');
$newResponse = $response->withJson($data, 203);
return $newResponse;
}
$data = array('status' => 'Successful login');
$newResponse = $response->withJson($data, 200);
return $newResponse;
}
and added routes for the methods.
How could i successfully authenticate with Ionic v3 and Angular v5?
I have a issue with my slim app, i want send json responses but with customed headers. My code is like follow:
index.php
require 'vendor/autoload.php';
require 'app/config.php';
require 'app/libs/api.cs.php';
$app = new Slim\App(
[
"settings" => $config,
"apics" => function() { return new APIHelper(); } //This is a class that contain a "helper" for api responses
]
);
require 'app/dependences.php';
require 'app/middleware.php';
require 'app/loader.php';
require 'app/routes.php';
// Run app
$app->run();
app/libs/api.cs.php (The "helper")
<?php
class APIHelper
{
public function sendResponse($response, $status='success' ,$code = 200, $message = "", $data = null)
{
$arrResponse = array();
$arrResponse['status'] = $status;
$arrResponse['code'] = $code;
$arrResponse['message'] = $message;
$arrResponse['data'] = $data;
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization, AeroTkn')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Content-Type','application/json')
->withHeader('X-Powered-By','My API Server')
->withJson($arrResponse,$code);
}
}
my routes file (app/routes.php)
$app->group('/foo', function () {
$this->get('', function ($req, $res, $args) {
return $this->apics->sendResponse($res, 'success' ,200, "Foo API Index By Get", null);
});
$this->post('', function ($req, $res, $args) {
try{
$oBody = $req->getParsedBody();
return $this->apics->sendResponse($res, 'success' ,200, "Foo API POST Response", $oBody);
}
catch(\Exception $ex){
return $this->apics->sendResponse($res, 'error' ,500, "Process Error", array('error' => $ex->getMessage()));
}
});
});
When i trying to run my app with request body, the result is the follow:
Headers:
connection →Keep-Alive
content-type →text/html
date →Wed, 30 Aug 2017 02:22:56 GMT
keep-alive →timeout=2, max=500
server →Apache
transfer-encoding →chunked
Body (returns as simple text and not json encoded)
{"status":"success","code":200,"message":"Foo API POST Response","data":{"one":"1", "two":"2"}}
I've trying put this class as a middleware, but i'm some confused in these subject.
Can you help me telling me if these method is good or where i'm bad.
Thanks to all and i hope for your answers! Nice day
Using Middleware is the ideal answer for your problem
Just add this function in your middeleware file
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
->withHeader('Content-Type','application/json');
->withHeader('X-Powered-By','My API Server');
});
I found the "error" was a kindergarden issue hahaha, I've download all my code from the web server for test in my machine, I have the same result, but i found that all my files had strange characters at start, so i re-save the files as utf-8 and the problem is solved. Little details that can create headaches!. Thanks to Nica and Ramy. Ramy: the solution was excellent, now the code are more organizated, i take this practice. Good day to all.
I'm creating my first api, and I chose to use Slim PHP, so far, I think it's a great lightweight framework to do the basics of what I need. The only issue I've really had was my route responses not returning the correct status codes. I want to return 200 on a successful login, and a 403 on a failed login with incorrect credentials. All I get back is a 200 no matter what it returns. The logic is working, because I can see the correct JSON being returned, just the status code doesn't get changed.
Index.php
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require 'vendor/autoload.php';
$app = new \Slim\App;
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
});
require_once 'api/login.php';
$app->run();
Login.php
$app->post('/api/login', function ($request, $response){
require_once 'db.php';
$q = "SELECT * FROM blog_admin WHERE username = ? AND password = ?";
$stmt = $mysqli->prepare($q);
$stmt->bind_param('ss', $user, $pass);
$user = $request->getParsedBody()['username'];
$pass = md5($request->getParsedBody()['password']);
if($stmt->execute()){
$stmt->store_result();
if($stmt->num_rows > 0){
$token = md5(uniqid($user, true));
date_default_timezone_set("America/Toronto");
$logged_in = date('Y/m/d');
$data = array(
"flash" => 'success',
"message" => '<strong>SUCCESS:</strong> You have entered the correct login information! Please wait while you are redirected...',
'_token' => $token,
'logged_in' => $logged_in
);
$q = "UPDATE blog_admin SET _token=?, last_logged_in=?";
$stmt = $mysqli->prepare($q);
$stmt->bind_param('ss', $token, $logged_in);
if($stmt->execute()){
$response->withJson($data, 200);
}else{
$data = array(
"flash" => 'danger',
"message" => '<strong>ERROR:</strong> Could not login! Please try again later!'
);
$response->withJson($data, 403);
}
}else{
$data = array(
"flash" => 'danger',
"message" => '<strong>ERROR:</strong> The Username/Password you have entered is incorrect. Please try again.'
);
$response->withJson($data, 403);
}
}else{
$data = array(
"flash" => 'danger',
"message" => '<strong>ERROR:</strong> Could Not Run the SQL'
);
$response->withJson($data, 500);
}
return $response;
});
I'm not sure what the issue might be, so any ideas will be much appreciated.
The PSR-7 Response which slim3 uses is a immutable value object, so it cannot be changed.
F.ex.
$response->withJson($data, 200);
Will not change $response it returns the changed Response so you either have to return this
return $response->withJson($data, 200);
or you need to reassign the variable with the new value, and then return it at the end of the route function.
$response = $response->withJson($data, 200);
// other code
return $response;