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

Php 如何在Laravel 5.2中以JSON格式返回403响应?,php,laravel-5,laravel-5.2,Php,Laravel 5,Laravel 5.2,我正在尝试用Laravel5.2开发一个RESTful API。我不知道如何以JSON格式返回失败的授权。目前,它抛出的是403页错误,而不是JSON 控制器:TenantController.php class TenantController extends Controller { public function show($id) { $tenant = Tenant::find($id); if($tenant == null) retu

我正在尝试用Laravel5.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;
    }
}
class TenantPolicy
{
    use HandlesAuthorization;
    public function show(User $user, Tenant $tenant)
    {
        $users = $tenant->users();
        return $tenant->users->contains($user->id);
    }
}
'api.can' => \App\Http\Middleware\ApiAuthorization::class,
策略:
TenantPolicy.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;
    }
}
class TenantPolicy
{
    use HandlesAuthorization;
    public function show(User $user, Tenant $tenant)
    {
        $users = $tenant->users();
        return $tenant->users->contains($user->id);
    }
}
'api.can' => \App\Http\Middleware\ApiAuthorization::class,

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

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

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

我们通过修改
App\exceptions\handler.php
中的异常处理程序,将其添加到
render
函数中,成功地解决了这个问题

public function render($request, Exception $e)
{
    if ($e instanceof AuthorizationException)
    {
        return response()->json(['error' => 'Not authorized.'],403);
    }
    return parent::render($request, $e);
}

您可以拦截异常

    try {
        $this->authorize('update', $data);
    } catch (\Exception $e)
    {
        return response()->json(null, 403);
    }

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

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


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

接受的答案有效,但是如果您不想为每个路由返回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);
    }
}
更新你的路线。现在,您可以通过调用
api来使用新的api验证中间件


此方法允许您在不修改全局异常处理程序的情况下返回特定路由的json。

我在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);
    }

    // ...
}

Akram,在
TenantPolicy.php
中,它将有一些函数,例如
update
store
,并且它将有不同的条件语句。那么,我应该在
yourconditiontrue
中添加什么呢?无论您的授权逻辑是如何返回true-false的,如果是这样,那么您必须对每个函数执行条件,让我更新一下关于Laravel策略的知识,并在晚上返回一个解决方案,我将使用第三方库,如dingo/api。它为您处理了这个问题,以及版本控制和转换器。这在Laravel 5.4
dd($e instaceof AuthorizationException)
中不起作用。它仍然有效。您的异常是否真的是AuthorizationException的实例?也许您忘记了使用“use”操作符导入AuthorizationException类?更准确地说,是catch
\illumb\Auth\Access\AuthorizationException