2016-11-29 67 views
1

我试图找到一种干净的方式来覆盖AuthorizationException,以便在策略失败时接收一个可以传回的动态字符串。Laravel 5.3当策略失败时传递AuthorizationException异常

事情我知道我可以做的是:

1)包住政策与一个try-catch控制器,然后再次抛出一个自定义异常,需要一个特定的字符串,这似乎有点冗长

2)abort(403, '...')在政策之前返回,这似乎是因为政策有点哈克已经做的工作​​

,然后在/例外/处理器::使我可以发送回响应JSON

有一个更好的方式来做到这一点,以获得在政策失败的答复中的消息?或者是1或2我的最佳选择。

+0

因此,如果引发AuthorizationException,您希望生成自定义错误? – atefth

+0

嗨@atefth yah有点像验证失败时,你得到的错误包,但在这种情况下,你会得到一个失败的政策包与消息,将根据失败的政策作为JSON响应而有所不同。 – mtpultz

回答

1

我注意到如果您在使用Laravel例外的策略中使用throw AuthorizationException($message),它会跳出策略,但会继续在控制器中执行,并且不会继续执行到Handler::render。我认为这是他们以某种方式处理异常,但我无法找到他们在做什么......所以如果有人发现这种情况,我仍然想知道。

如果你创建自己的AuthorizationException扔它,它就会如预期停止执行,并放到Handler::render所以我最终加入这个方法我的政策:

use App\Exceptions\AuthorizationException; 

// ... removed for brevity 

private function throwExceptionIfNotPermitted(bool $hasPermission = false, bool $allowExceptions = false, $exceptionMessage = null): bool 
{ 
    // Only throw when a message is provided, or use the default 
    // behaviour provided by policies 
    if (!$hasPermission && $allowExceptions && !is_null($exceptionMessage)) { 

     throw new \App\Exceptions\AuthorizationException($exceptionMessage); 
    } 

    return $hasPermission; 
} 

新的异常,在政策投掷只在\App\Exceptions

namespace App\Exceptions; 

use Exception; 

/** 
* The AuthorizationException class is used by policies where authorization has 
* failed, and a message is required to indicate the type of failure. 
* --- 
* NOTE: For consistency and clarity with the framework the exception was named 
* for the similarly named exception provided by Laravel that does not stop 
* execution when thrown in a policy due to internal handling of the 
* exception. 
*/ 
class AuthorizationException extends Exception 
{ 
    private $statusCode = 403; 

    public function __construct($message = null, \Exception $previous = null, $code = 0) 
    { 
     parent::__construct($message, $code, $previous); 
    } 

    public function getStatusCode() 
    { 
     return $this->statusCode; 
    } 
} 

处理异常,并提供在Handler::render()以JSON响应消息:

public function render($request, Exception $exception) 
{ 
    if ($exception instanceof AuthorizationException && $request->expectsJson()) { 

     return response()->json([ 
      'message' => $exception->getMessage() 
     ], $exception->getStatusCode()); 
    } 

    return parent::render($request, $exception); 
} 

我也将其从登录Handler::report中删除。

-1

Laravel确实有一个选项来传递参数来定制在通过Gate类的实施GateContract访问的Controller类的authorize()方法由Gate门面提供错误

然而,他们似乎忘了这些参数传递给负责返回错误消息allow()/deny()方法,在HandlesAuthorization特质实现。


您需要通过以下步骤来传递这些参数:

  1. 修改authorize方法在vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php文件

    public function authorize($ability, $arguments = []) { 
        $result = $this->raw($ability, $arguments); 
        if ($result instanceof Response) { 
         return $result; 
        } 
    
        return $result ? $this->allow() : $this->deny($arguments); 
    } 
    
  2. 呼叫authorize从一个额外的参数控制,即:自定义$message -

    $message = "You can not delete this comment!"; 
    $response = $this->authorize('delete', $message); 
    

我已经做了pull request来解决这个问题,希望有人很快就会合并。

+0

不错,我们使用的模型策略'$ user-> can(...);'所以我会寻找这种相同类型的解决方案,看看它是否工作。此外,看起来像你的公关已暂时/永久搁置:( – mtpultz