I'm new to Laravel (we're using 5.0 at work). Right now, when we respond to an API request in a Controller, we are rewriting the same code over and over to respond to unauthorized actions. For example,
public function getUsers(){
if (Entrust::can('users.view')){
$users = Users::get();
return response()->done($users, 200);
} else {
return response()->unauthorized('users.view');
}
}
It gets more and more complicated if we have different permissions that can allow an API request to succeed.
I'd like to simply throw an exception of some sort if the user cannot perform the API request. For example,
public function getUsers(){
require('users.view'); // throws an UnauthorizedException if current user doesn't have 'users.view' permission
$users = User::get();
return response()->done($users, 200);
}
public function someOtherMethod(){
if (!Entrust::can('permission1') && !Entrust::can('permission2')){
throw new UnauthorizedException(['permission1', 'permission2']);
}
// some other stuff
}
But I don't know what code calls the API function, nor where to wrap that call in a try/catch. It's easy enough to code the UnauthorizedException, and easy to transform it into json, but where do I put the handler? As I said, I'm new to Laravel, and I don't know how it handles these exceptions.
Ideally, whatever solution I find, I'd like to extend it to other exceptions so we can have consistent json responses based on common exceptions.
Instead of repeating your code, take a look at implementing the authorization check with Middleware.
Related
I'm using the Laravel Swoole Coroutine go function to do a HTTP request in order to achieve better performance. When I get the response from the external service, a new entry is created in the database with the data from the external service.
I want to be able to return a response from the controller with that new DB record. However, it appears that anything outside the go does not have access to anything that got assigned in the go function. I understand that that happens in a separate thread, but is there a way to implement this so that I can have access to the results inside the go function?
Please note that I have coroutine enabled globally and I only to use function as shown below:
public function store(User $user, Request $request) {
go(function () {
// get data from external API using Laravel HTTP Client
...
$user = User:create($data);
return response($user, 201)->send();
});
}
I have tried using the WaitGroup(), but it complains that the event loop has already been started if I wrap it with the Co\run function.
I'm using CakePHP 3.5 and two of the methods I want to use are deprecated and I can't find an alternative.
The methods are:
$this->response->send();
$this->response->stop();
I want to redirect to a different page and stop the execution of the current method. I've tried calling die() after my redirect and it doesn't work.
According to the migration guide the methods have been made obsolete.
Any thoughts?
Edit:
I'm trying to redirect users without access to certain pages. This is in the initialize() method in the controllers.
if ($allowedAccess) {
$this->Flash->error("Insufficient rights to access that location");
$this->redirect($this->referer());
// FIXME - find alternative to deprecated methods
return $this->response;
$this->response->send();
$this->response->stop();
}
Are you trying this in a controller? Simply return the response object from your controllers method:
public function index() {
// Some code
return $this->response;
}
send() was just a wrapper around phps exit(). Use exit() if you need to somewhere.
What happens when you return the response is that the ActionDispatcher processes the return value and if it's a Response object. See the __invoke() method.
The response will go through the middleware layer and will be finally send by the ResponseEmitter which is used by the Server. Check your webroot/index.php to see it:
// Bind your application to the server.
$server = new Server(new Application(dirname(__DIR__) . '/config'));
// Run the request/response through the application
// and emit the response.
$server->emit($server->run());
I'm building a RESTful API using Symfony2, FOSRestBundle and an OAuth 2 server library.
For any given request, there are a number of possible responses and status codes that I can return to the client.
Take for example the process of getting a user:
<?php
class UserController extends CustomBaseController {
/**
* Get a user
* #Get("/users", name="users_get")
*/
public function getAction(Request $request) {
// Ensure a valid access token is present
$this->validAccessTokenOrExit();
$user = $this->getUser();
return $this->handleView($this->view($user, 200));
}
}
Ideally I would like to have the validAccessTokenOrExit() function terminate the request and return the 401 status code with an appropriate message. This means I can handle authentication in this function and reuse it in several actions across the API.
However I can't seem to find a way of terminating the response from another function, and I always have to return a Response from the action called.
Are there any clean solutions to accomplish this or something similar?
If you throw an exception that has the interface Symfony\Component\HttpKernel\Exception\HttpExceptionInterface (Symfony\Component\HttpKernel\Exception\HttpException for example) with the status code set (first parameter as 401 for HttpException) it will be handled by the HttpKernel in the way that you are expecting.
For example..
throw new HttpException(401, 'Something went wrong');
.. will be turned into a response with 401 as the status code.
You can use $this->createAccessDeniedException('message') within a controller.
This will create AccessDeniedException, terminate the current request and return a 403 with your message.
I did faced this situation and for time being I call the terminating function with return. Return false from function when valid.
if($r=$this->validAccessTokenOrExit()){
return $r;
}
Alternatively I use following two methods for redirecting or rendering a view form another function and terminating flow.
Redirection:
header('location:'. $this->generateUrl('deals_product_view', array('id' => 1)));
exit;
Rendering a view:
$response = new Response();
$response->setContent($this->renderView($view_file, $params ));
$response->send();
exit;
Is there a way to call a routine before each route in Slim PHP? I have a RESTful API and I want to validate the login before calling the API methods. My code looks like:
$app = new Slim();
$app->get('user/:id', function($id) use($app){
$user = API::getUser($id);
if($user){
$app->response->status(200);
}else{
$app->response->status(404);
}
});
The API makes the request and process a JSON response. I want to attach a precondition to allow the request, something like a callback. The API has a method API::validate($token) that returns true or false, I want to catch this and return status code 401 if authentication fails. Some methods like API::login() and API::register() don't need this validation.
First i strongly advice you to read ALL the documentation. It isn't that big and you'll get a good introduction to the framework. http://docs.slimframework.com/
You don't need a routine but a hook that gets called before each routine. That's the way slim is structured.
A easy solution would be to keep the non protected pages in a array, and in that hook check if the request is protected or not.
$app->hook('slim.before.dispatch', function() use ($app) {
$publicRoutes = array('login', 'welcome');
if(!in_array($app->router()->getCurrentRoute(), $publicRoutes)
// Get the token
$result = API::validate($token);
if(!$result) {
$app->redirect('/login');
}
});
If you want to handle a more complex process with permissions levels, oauths, etc you'll rather use a Middleware. I like them because it's the right way to do this kind of tasks with Slim, and you can reuse them.
I am calling one function from onBootStrap() to authorize user, in that function I am using header information to verify the user.
If this is not correct, I want to stop execution here(onBootStrap()) without even calling the actual API and return some response to the user .
User should get some response because then only user can know what's the problem.
How I can return response from there?
Simply said, onBootstrap is not sufficient for this. Usually, you have two stages in your application. The first is bootstrapping, the second is running. During run you can authorize users and return responses, during bootstrap this is not possible.
The reason is simple, you might have another module overriding it's behaviour. If you stop bootstrapping after your module, you can stop the execution of these modules. It's better to move the logic to run. This run stage is defined with various listeners, of which the first is route. There isn't much going on after bootstrap and before route, so in terms of performance it's neglectable.
A code example:
use Zend\Mvc\MvcEvent;
use Zend\Json\Json;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$em = $app->getEventManager();
$em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($app) {
// your auth logic here
if (!$auth) {
$response = $e->getResponse();
$response->setStatusCode(403);
$response->setContent(Json::encode(array(
'error' => 12345,
'message' => 'You are not authorized for this request',
));
return $response;
}
}, PHP_INT_MAX);
}
}
The listener is attached at an very early stage (PHP_INT_MAX) so the check happens as first in the complete route stage. You can also choose for quite a high number (like, 1000) so you can hook in this event before user authorization.