CakePHP: Redirect to login from custom component - cakephp

In a custom component I am making API calls. If the API call returns 403 I want to logout the user and redirect to the login. With the following code I get a response object without knowing if the response is a redirect or if the response is containing the data of the request. Besides get I have also other methods implemented in the Component so that I have at the end over 50 times a call to the RestAPIComponent.
Calling the RestAPIComponent
public function view($id)
{
$resource = $this->__getSingularResourceName();
$$resource = $this->RestApi->get($id)->json;
$this->set(compact($resource));
}
RestAPIComponent
public function get($id = null, array $query = [], $action = null)
{
$path = (is_null($id) === false) ? $id : '';
$response = $this->_http->get($path . '/' . $action, $query, $this->_getAuthHeader());
return $this->_handleResponse($response);
}
private function _handleResponse(Response $response)
{
if ($response->statusCode() == 403) {
$this->Cookie->delete(TOKEN);
$this->Cookie->delete(USER);
$controller = $this->_registry->getController();
return $controller->redirect($controller->Auth->logout());
} else {
return $response;
}
}

There may be following reasons behind it, getting the 403 error using auth component --
1.It is possible to get a 403 via code. Check this out from the CakePHP docs (http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#handling-unauthenticated-requests): If authenticator returns null, AuthComponent redirects user to login action. If it’s an ajax request and AuthComponent::$ajaxLogin is specified that element is rendered else a 403 http status code is returned.
2.Multiple Ajax calls shouldn't be the causing factor of a 403 error.
3.The standard routing is handled by CakePHP itself. If you need some different routing, you should configure this in routes.php. I would say using .htaccess is only for a really extreme routing need and should be a last resort.
4.Yes that could be a cause, since you would no longer be logged in, thus get Auth 403s
For more detail -- you could visit the link Common reasons behind 403 errors

Related

Setting a header in CakePHP (MVC)

I'm trying to integrate PayPal's IPN code into CakePHP 3.
namespace App\Controller;
use PayPal\Api\PaypalIPN;
class IpnController extends AppController
{
public function index()
{
$this->autoRender = false;
$ipn = new PayPalIPN();
// Use the sandbox endpoint during testing.
$ipn->useSandbox();
$verified = $ipn->verifyIPN();
if ($verified) {
/*
* Process IPN
* A list of variables is available here:
* https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/
*/
}
// Reply with an empty 200 response to indicate to paypal the IPN was received correctly.
header("HTTP/1.1 200 OK");
}
}
This is failing to validate on PayPal's end and I'm suspecting it has to do with setting the headers in the controller view.
Is there a way to set the header properly in CakePHP's controller.
I had this code running stand alone (in just a php file) and it seemed to work just fine.
You should not output any data in your controller action - that means you should not use echo, header() or any function or construct that would return anything to browser. If you do, you will encounter a "headers already sent" error.
If you want to set headers, you should use withHeader() or withAddedHeader() methods of Cake\Http\Response.
For status codes, you also have withStatus() method:
$response = $this->response;
$response = $response->withStatus(200,"OK");
return $response; // returning response will stop controller from rendering a view.
More about setting headers can be found in docs:
Setting response headers in CakePHP 3
Cake\Http\Response::withStatus()
Maybe that's not very Cakish, but actually one can send headers this way - it just have to be followed by die; or exit; to prevent app from further response processing.
Anyway, for sure your problem is not associated with headers. IPN seems to doesn't work properly with Paypal Sandbox. Maybe you should try it other way with ApiContext class?

Getting 302 error while loading javascript library in react

I am trying to import one javascript library in my react project. I am getting the 302 status on the Network panel.
I can see the status 302 ( Not to be modified) in the dev toolbar on browser Netwrok tab.
Can anyone let me know the cause of this issue ?.
The error is not react related it is due to Ajax request.Which is returned by server.
HTTP 302 is used for redirection. My guess is that there is some sort of server error and you are being redirected to an error page using 302. Check the server logs for errors.
Else try the following,
Adding a custom header to the response:
public ActionResult Index(){
if (!HttpContext.User.Identity.IsAuthenticated)
{
HttpContext.Response.AddHeader("REQUIRES_AUTH","1");
}
return View();
}
Or:
Binding a JavaScript function to the ajaxSuccess event and checking to see if the header exists:
$(document).ajaxSuccess(function(event, request, settings) {
if (request.getResponseHeader('REQUIRES_AUTH') === '1') {
window.location = '/';
}
});

CakePHP: Is there a easy way to send custom status code and send serialized vars in controller?

I'm building a restful API in a controller. I want to respond to GET resources that do not exist with a 404 status response and send a message in JSON. Like this:
public function view($id = null)
$this->request->allowMethod(['get']);
try {
$pessoa = $this->Users->get($id);
} catch (RecordNotFoundException $e){
$this->set(['message'=>'User not found']);
return $response->withStatus(404);
}
$this->set(compact('users'));
}
But it does not returns the message. I guess this 'return' interferes on the variable definitions flow.
I think you use Cakephp 3.x
See Response section on CookBook.
And try it:
$this->response = $this->response->withStatus(404);

Cakephp 3 - CRUD plugin - Use id from auth component

Currently, I'm using the CRUD v4 plugin for Cakephp 3. For the edit function in my user controller it is important that only a user itself can alter his or her credentials. I want to make this possible by inserting the user id from the authentication component. The following controller method:
public function edit($id = null){
$this->Crud->on('beforeSave', function(\Cake\Event\Event $event) {
$event->subject()->entity->id = $this->Auth->user('id');
});
return $this->Crud->execute();
}
How can I make sure I don't need to give the id through the url? The standard implementation requires the url give like this: http://domain.com/api/users/edit/1.json through PUT request. What I want to do is that a user can just fill in http://domain.com/api/users/edit.json and send a JSON body with it.
I already tried several things under which:
$id = null when the parameter is given, like in the example above. Without giving any id in the url this will throw a 404 error which is caused by the _notFound method in the FindMethodTrait.php
Use beforeFind instead of beforeSave. This doesn't work either since this isn't the appropriate method for the edit function.
Give just a random id which doesn't exist in the database. This will through a 404 error. I think this is the most significant sign (combined with point 1) that there is something wrong. Since I try to overwrite this value, the CRUD plugin doesn't allow me to do that in a way that my inserting value is just totally ignored (overwriting the $event->subject()->entity->id).
Try to access the method with PUT through http://domain.com/api/users.json. This will try to route the action to the index method.
Just a few checks: the controllerTrait is used in my AppController and the crud edit function is not disabled.
Does anyone know what I'm doing wrong here? Is this a bug?
I personally would use the controller authorize in the Auth component to prevent anyone from updating someone else's information. That way you do not have to change up the crud code. Something like this...
Add this line to config of the Auth component (which is probably in your AppController):
'authorize' => ['Controller']
Then, inside the app controller create a function called isAuthorized:
public function isAuthorized($user) {
return true;
}
Then, inside your UsersController you can override the isAuthorized function:
public function isAuthorized($user) {
// The owner of an article can edit and delete it
if (in_array($this->request->action, ['edit'])) {
$userId = (int)$this->request->params['pass'][0];
if ($user['id'] !== $userId) {
return false;
}
}
return parent::isAuthorized($user);
}

ionic laravel XMLHttpRequest cannot load

i am new to this and i am trying to login and get a token so the ionic and laravel can communicate. I am using satellizer and jwt on laravel. on post man i get the token back:
this is what i am getting loging in from ionic:
[enter image description here][2]
the error says:
XMLHttpRequest cannot load http://localhost:8000/api/authenticate. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
and yeah, on my laravel side, i have included
header("Access-Control-Allow-Origin: *");
what am i missing here, thank you
There are many factors to why this happens. the error may happen because you have no access headers and the browsers gets this and blocks your requests.
It also happens when you your server experiences internal errors like 500,403,401 etc. you may have added headers to the requests life cycle(like in the middleware to filter all api requests) in your laravel app but sometimes an error 500 or even an echo or dd() interrupts the whole request life cycle and returns the errors WHICH the browser can't interpret through an ajax call and therefore it loses the headers you implicitly added thus the browser goes back to the preflight request error..
The only solution I suggest is proper error handling in your code and returning errors in a response and return it in json format.
public function someController extends Controller{
public function Foo(Request $request){
$input_bag = [
'some input' => first_$input,
'another important input' => $second_input,
];
$i = 0;
foreach ($input_bag as $key => $value) {
$value = trim($value);
if (empty($value)) {
$error_bag[$i] = "$key empty";
$i++;
} else {
//
}
}
//filter of false or null values
if (array_filter($error_bag)) {
return response()->json($error_bag, 400);
}
}
this returns a json response of the errors while running the code. and good use of try catches and returning the appropriate responses could make your debugging life easy.

Resources