Laravel custom error page if authorization fails - laravel

I am trying to show a custom 403 file in laravel when authorization fails in my edit request.
I tried forbiddenResponse() but as it turns out it has been eliminated.
Then I tried failedauthorization() but this does not redirect as well and allows me to edit.
here is my request file
public function authorize()
{
$job_posting_id = $this->route('id');
$job_posting = Job_postings::where('id', $job_posting_id)->where('user_id', user()->id)->exists();
if($job_posting){
return true;
}
return false;
}
public function failedAuthorization()
{
return redirect('errors.dashboard.parent.403');
}
I have a folder called errors and inside there I have dashboard folder and parent where the error file is located.
How can I redirect to that page if authorization fails?

return abort('403')
Laravel documentation:
https://laravel.com/docs/5.4/errors#http-exceptions
if you make everything like in docs, you'll achieve:
url will stay the same.
template resources/views/errors/403.blade.php will be shown.
aslo response will have Status Code:403 Forbidden
do you want change url into http://www.examlpe.com/error403 ?
return abort('403') doesn't make redirect. It just shows a client that error has occured.
In your case it is easier to show different content in single script, than different scripts. Try to leave single error script as an "entry point". And in that script change output for different users. Imagine that 403.blade.php is a layout for a number of 403 error pages.

In your laravel folder open app/Exceptions/Handler.php paste the following code. That will return custom error page for 403 and 500 error.
public function render($request, Exception $exception)
{
if ($exception instanceof CustomException) {
return response()->view('errors.custom_all', [], 500);
}
if ($exception instanceof \Spatie\Permission\Exceptions\UnauthorizedException) {
return response()->view('errors.custom', [], 403);
}
return parent::render($request, $exception);
}

public function authorize()
{
$job_posting_id = $this->route('id');
$job_posting = Job_postings::where('id', $job_posting_id)->where('user_id', user()->id)->exists();
if($job_posting){
return true;
}
return redirect('/error');
}
public function failedAuthorization()
{
return view('errors.dashboard.parent.403');
}
In your route
Route::get('error', 'YourController#failedAuthorization');

Go to the file Exceptions/Handler.php's report method.
public function report(Exception $e)
{
if(!Auth::check())
{
// Do whatever you want - redirect or return something
}
if($e instanceof HttpException && $e->getStatusCode() == 403)
{
// Do whatever you want - redirect or return something
}
return parent::report($e);
}
And wherever your authorisation failed, just write abort(403)
Hope this will help :)

Related

Handle Exception From Within Method

I am implementing payments for my website using the API of an external service (ie. the service of the payment provider).
Let's say the user clicks 'BUY', and then we go to my controller which says something along the lines of:
public function buyFunction() {
$result = $this->ExternalService->pay();
if ($result->success == true) {
return 'We are happy';
}
}
I have also created the aforementioned externalService which has the pay() method:
class ExternalService {
public function pay() {
response = //Do stuff with Guzzle to call the API to make the payment
return response;
}
}
Now, sometimes things go wrong.
Let's say the API returns an error - which means that it throws a GuzzleException - how do I handle that?
Ideally, if there is an error, I would like to log it and redirect the user to a page and tell him that something went wrong.
What I've tried
I have tried using a try/catch statement within the pay() function and using abort(500) but this doesn't allow me to redirect to the page I want to.
I have tried using a try/catch statement within the pay() function and using return redirect('/mypage') but this just returns a Redirect object to the controller, which then fails when it tries to call result->success
I have tried using number 2 but also adding a try/catch block to the controller method, but nothing changed.
In the end, I have found two solutions. In both, I use a try/catch block inside the pay() method. Then I either return 0; and check in the controller if (result == 0) or I use abort( redirect('/mypage') ); inside the try/catch block of the pay() method.
What is the right way to handle this?
How to use the try/catch blocks?
In my experience, avoid handling exceptions let them pass through and handle them accordingly with try catches. This is the most pragmatic approach. Alternatively you will end up checking result is correct in weird places, eg. if ($result) {...}. Just assume it went good, except if the exception is thrown. Bonus: never do Pokemon catches with Exception $e unless you specifically needs it!
class ExternalService {
public function pay() {
try {
response = $client->get(...);
} catch (BadResponseException $exception) {
Log::warning('This should not happen check payment api: ' . $exception->getMessage());
throw new PaymentException('Payment did not go through');
}
return response;
}
}
Assuming you have your own Exception.
class PaymentException extends HttpException
{
public function __construct(?\Exception $previous = null)
{
parent::__construct(Response::HTTP_BAD_REQUEST, 'Unexpected error processing the payment', $previous);
}
}
This enables you to handle the flow in a controller, where it would make sense to handle the redirect. Sometimes if the exception is very integral or common to the web app, it can also be handled by the exception handler instead.
class PaymentController {
public function pay(PaymentService $service) {
try {
$payment = $service->buyFunction();
} catch (PaymentException $exception) {
return redirect()->route('app.payment.error');
}
return view('app.payment.success', compact('payment'));
}
}

Laravel dusk if browser->assertSee then do this

Is there a way to proceed with a test even if assertSee returns with an error.
This is my current code:
$browser->visit('https://urltotest.co.uk/find-an-engineer/')
->type("EngineerId", $engineerId)
->click('#checkEngineer');
$test = $browser->assertSee("Engineer cannot be found");
What I would like to be able to do is go:
if ($test == false) {
return false;
} else {
return $browser->text('.engineer-search-results-container .search-result .col-md-8 .row .col-xs-10 h3');
}
But when the assertSee fails all I get back is:
Did not see expected text [Engineer cannot be found] within element [body].
As an exception. Any way I can proceed if it can't find that element?
You should be able to achieve this using a try catch to catch the exception:
try {
$browser->assertSee("Engineer cannot be found");
} catch(\Exception $e) {
return false;
}
To note, I do not know if there is a method such as $browser->fail() (like phpunit's $this->fail()) which will fail the test for you.

How to handle 'throw new DecryptException('The payload is invalid.')' on Laravel

I have small Laravel project working on Crypt class. It work fine for both Crypt::encrypt(..) and Crypt::decrypt(..). But I have problem if I directly change on crypted value then try to capture exception. For example, my crypted value is
zczc1234j5j3jh38234wsdfsdf214
Then I directly add some words as below.
zczc1234j5j3jh38234wsdfsdf214_addsometext
I try to decrypt and get error as below
throw new DecryptException('The payload is invalid.')
So, I try to capture exception with render method.
public function render($request, Exception $exception)
{
if ($exception instanceof \Illuminate\Contracts\Encryption\DecryptException) {
dd("error");
return route('login')->withError('Your DB may be hacked');
}
return parent::render($request, $exception);
}
I do not known why method not fire, Appreciated&thanks for all comment.
You should handle this with
use Illuminate\Contracts\Encryption\DecryptException;
try {
$decrypted = decrypt($encryptedValue);
} catch (DecryptException $e) {
//
}
check https://laravel.com/docs/5.8/encryption

.NET web api HttpPatch returning 403 forbidden

I have a simple resource that provides a list of translations. The get end point takes a language and returns a dictionary of translations. Any updates are going to be on just one translation, so I figured that would be appropriate to do as a patch.
In my api controller, I can make a put work just fine, but any call I make to my patch end point is giving me a 403 forbidden error and I don't understand why.
[HttpGet]
// GET api/<controller>
public Dictionary<string,string> Get(String id)
{
return TranslationSvc.GetTranslatedStrings(id);
}
[HttpPatch]
public TranslationEntry Patch(TranslationEntry data)
{//403 prevents this end point from ever executing
if (TranslationSvc.UpdateTranslation(data.Lang, "", data.Translation.Key, data.Translation.Value))
{
return data;
}
else
{
//return a 500 error;
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
[HttpPut]
public TranslationEntry Put(TranslationEntry data)
{//works, but technically a put should be the full resource which is the full collection
if (TranslationSvc.UpdateTranslation(data.Lang, "", data.Translation.Key, data.Translation.Value))
{
return data;
}
else
{
//return a 500 error;
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
I found the problem. I had forgotten that I was running against a local proxy that simulated our single sign on behaviors. That local proxy was configured to deny anything but GET and post actions basically. Sorry for the false alarm question :)

How to 'unset' session save handler?

For some reason I have to initialize session with default save handler.
Previous code explicitly sets custom handler with session_set_save_handler().
Changing previous code is not a realistic option in my situation, so does anyone know how to restore handler to default eg is there session_restore_save_handler or session_unset_save_handler functions or equivalents?
As of PHP 5.4 you can revert to the default session handler by instantiating the SessionHandler class directly:
session_set_save_handler(new SessionHandler(), true);
Here I have to answer on my own question since no one said anything:
First, there is no session_restore_save_handler or session_unset_save_handler given from PHP and (by so far) no native way to get things back as they were before. For some reason, PHP team didn't give us option to juggle with session handlers in this way.
Second, native session mechanism can be emulated with following code
class FileSessionHandler
{
private $savePath;
function open($savePath, $sessionName)
{
$this->savePath = $savePath;
if (!is_dir($this->savePath)) {
mkdir($this->savePath, 0777);
}
return true;
}
function close()
{
return true;
}
function read($id)
{
return (string)#file_get_contents("$this->savePath/sess_$id");
}
function write($id, $data)
{
return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
}
function destroy($id)
{
$file = "$this->savePath/sess_$id";
if (file_exists($file)) {
unlink($file);
}
return true;
}
function gc($maxlifetime)
{
foreach (glob("$this->savePath/sess_*") as $file) {
if (filemtime($file) + $maxlifetime < time() && file_exists($file)) {
unlink($file);
}
}
return true;
}
}
$handler = new FileSessionHandler();
session_set_save_handler(
array($handler, 'open'),
array($handler, 'close'),
array($handler, 'read'),
array($handler, 'write'),
array($handler, 'destroy'),
array($handler, 'gc')
);
register_shutdown_function('session_write_close');
This logic is closest to PHP's native session dealing one, but with , of course, unpredictable behavior in different circumstances. All I can right now conclude is that basic session operations is full covered with it.

Resources