如何在Laravel 5.2中以JSON格式返回403响应?

时间:2016-07-26 04:11:14

标签: php laravel-5 laravel-5.2

我正在尝试使用Laravel 5.2开发RESTful API。我偶然发现如何以JSON格式返回失败的授权。目前,它正在抛出403页面错误而不是JSON。

控制器:TenantController.php

class TenantController extends Controller
{
    public function show($id)
    {
        $tenant = Tenant::find($id);
        if($tenant == null) return response()->json(['error' => "Invalid tenant ID."],400);
        $this->authorize('show',$tenant);
        return $tenant;
    }
}

政策:TenantPolicy.php

class TenantPolicy
{
    use HandlesAuthorization;
    public function show(User $user, Tenant $tenant)
    {
        $users = $tenant->users();
        return $tenant->users->contains($user->id);
    }
}

授权目前工作正常,但它显示403禁止页面而不是返回json错误。是否可以将其作为403的JSON返回?并且,是否可以使所有失败的授权(不仅仅是在此控制器中)全局化?

6 个答案:

答案 0 :(得分:22)

我们设法通过修改App\Exceptions\Handler.phprender添加public function render($request, Exception $e) { if ($e instanceof AuthorizationException) { return response()->json(['error' => 'Not authorized.'],403); } return parent::render($request, $e); } 函数中的例外处理程序来解决此问题。

{{1}}

答案 1 :(得分:2)

是的,在您的策略中创建一个简单的before方法,该方法将在所有其他授权检查之前执行,

public function before($user, $ability,Request $request)
{
    if (!yourconditiontrue) {
         if ($request->ajax()) {
            return response('Unauthorized.', 401);
        } else {
            return abort('403');
        }
    }
}

答案 2 :(得分:2)

您可以截取异常

Array.prototype.includes = function (object) {
  return !!+~this.indexOf(object);
};

答案 3 :(得分:1)

对于最新版本的Laravel,从现在的7.x版本开始,

通常设置请求标头'Accept'=>'application / json'会告诉Laravel您希望返回json响应。

对于错误,您还需要通过在.env文件上设置 APP_DEBUG = false 来关闭调试,这将确保响应为json并且未提供stacktrace。

答案 4 :(得分:1)

我在 Laravel 7.3 版中也遇到了同样的问题,其中 AuthorizationException 没有被捕获。我知道我们必须在 Handler.php 中包含 AuthorizationException 像

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

use Illuminate\Auth\AuthenticationException;
use Illuminate\Auth\Access\AuthorizationException;

use Throwable;
use Exception;
use Request;
use Response;

class Handler extends ExceptionHandler
{
    // ...

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable  $exception
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Throwable
     */
    public function render($request, Throwable $exception)
    {
        if ($exception instanceof AuthorizationException)
        {
            return response()->json(['message' => 'Forbidden'], 403);
        }
        if ($exception instanceof ModelNotFoundException && $request->wantsJson()) {
            return response()->json(['message' => 'resource not found')], 404);
        }
        
        return parent::render($request, $exception);
    }

    // ...
}

仅供参考,如果您只是使用以下语句添加 AuthorizationException

<块引用>

使用授权异常;

还是不行。所以我们必须指定完全限定的命名空间路径。

答案 5 :(得分:0)

可接受的答案有效,但是如果您不想为每条路线都返回json,则可以使用中间件进行处理。

有关此操作的简要概述:

创建一个ApiAuthorization类并扩展您的主要auth类。

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Auth\Access\AuthorizationException;

class ApiAuthorization extends Authorize
{
    public function handle($request, Closure $next, $ability, ...$models)
    {
        try {
            $this->auth->authenticate();

            $this->gate->authorize($ability, $this->getGateArguments($request, $models));
        } catch (AuthorizationException $e) {
            return response()->json(['error' => 'Not authorized.'],403);
        }

        return $next($request);
    }
}

将中间件添加到$routeMiddleware中的App\Http\Kernel.php

'api.can' => \App\Http\Middleware\ApiAuthorization::class,

更新您的路线。现在,您可以通过调用类似于the example in the docsapi.can来使用新的api auth中间件

    Route::get('tenant', [
        'as' => 'api.tenant',
        'uses' => 'TenantController@show'
    ])->middleware('api.can:show,tenant');

此方法允许您返回特定路由的json,而无需修改全局异常处理程序。