我正在尝试使用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返回?并且,是否可以使所有失败的授权(不仅仅是在此控制器中)全局化?
答案 0 :(得分:22)
我们设法通过修改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);
}
函数中的例外处理程序来解决此问题。
{{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 docs的api.can
来使用新的api auth中间件
Route::get('tenant', [
'as' => 'api.tenant',
'uses' => 'TenantController@show'
])->middleware('api.can:show,tenant');
此方法允许您返回特定路由的json,而无需修改全局异常处理程序。