My authorize function is always failing in laravel-5.8? - laravel

I created one policy inside create function i am checking weather this user can able to create records and i am registering the Model and policy in the AthServiceProvider.php after that i am checking inside the controller by using $this->authorize('create') it's failing always even the user is valid,can you please help me how to resolve this issue
Error:- This Action is unathorized
restaurentContoller.php
class RestaurentsController extends Controller
{
protected $repository;
public function __construct(RestaurentRepository $repository){
$this->repository = $repository;
}
public function postRestaurent(RestaurentRequest $request){
$data = $request->all();
$data['admin_id'] = $this->getAccountId($request);
$this->authorize('create');
$rest = $this->repository->create($data);
return response()->json(fractal($rest,new RestuarentTransformer));
}
}
RestaurentPolicy.php
public function create(User $user)
{
return ($user->admin_id=1) ? true : false;
}
api.php
Route::post('/postRest',[RestaurentsController::class,'postRestaurent'])->middleware(['CheckAdmin']);

If you use Request Classes you have to change authorize method return false to true
class RestaurentStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return false;
}
}

Related

Laravel - Instantiate object and keep it within all controller's methods

I'm working with this case where I need to instantiate an object after a form is submitted in a controller. Everything's working fine until I call this object (as a property) from another method. It appears to be null.
If I intentiate the object from constructor method, I have no problem at all.
I can't keep this object in session because of closure.
Here's what i got so far.
// Version with the object iniate within the constructor that's working
class SearchConsoleController extends Controller
{
private $console;
protected function __construct() {
$callback = route('searchconsole.callback') ;
$this->console = $this->setConsole(env('CLIENT_ID'), env('CLIENT_SECRET'), $callback);
}
private function setConsole($cliendId, $cliendSecret, $callback){
$console = new Console(new Google_Client(), $cliendId, $cliendSecret, $callback);
return $console;
}
public function index(Request $request) {
return view('searchconsole.index')->with('authUrl', $this->console->getAuthUrl());
}
public function callback(Request $request){
if ($request->has('code')) {
$this->console->acceptCode($request->get('code'));
return redirect()->action('SearchConsoleController#listSites', [$request]);
}
else{
die('error');
}
}
Now the version which i'm stucked wih
class SearchConsoleController extends Controller
{
private $console;
private $callback;
protected function __construct() {
$this->callback = route('searchconsole.callback') ;
}
private function setConsole($cliendId, $cliendSecret, $callback){
$console = new Console(new Google_Client(), $cliendId, $cliendSecret, $this->callback);
return $console;
}
public function index(Request $request) {
// VIEW WITH A FORM FROM WHICH I GET CLIENT_SECRET & CLIENT_ID var
return view('searchconsole.index');
}
public function getAuthUrl(Request $request) {
// FORM FROM INDEX IS SUBMITTED
$clientId = ($request->has('google-client-id')) ?
$request->get('google-client-id') :
null
;
$clientSecret = ($request->has('google-client-secret')) ?
$request->get('google-client-secret') :
null
;
$this->console = $this->setConsole($clientId, $clientSecret, $this->callback);
return $this->console->getAuthUrl();
}
public function callback(Request $request){
if ($request->has('code')) {
// ***** MY PROBLEM *********
$this->console->acceptCode($request->get('code')); // HERE $this->console IS NULL;
// *******************
return redirect()->action('SearchConsoleController#listSites', [$request]);
}
else{
die('error');
}
}
I just can't figure out how I can do this so console is still available
UPDATE :
following #iamab.in advice, i looked into Service Provider but i just dont know how i can instante the Console Object within the service provider.
Here's what i've done.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Helpers\Console;
use Google_Client;
use Illuminate\Support\Facades\Route;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(Console::class, function() {
$request = app(\Illuminate\Http\Request::class);
$clientId = ($request->has('google-client-id')) ?
$request->get('google-client-id') :
null
;
$clientSecret = ($request->has('google-client-secret')) ?
$request->get('google-client-secret') :
null
;
$callback = Route::get()->name('searchconsole.callback');
return new Console(new Google_Client(), $clientId, $clientSecret, $callback);
});
}
public function boot(){}
....
I just dont know how and where to implement it.
Thanks again
Update#2 :
okay my solution was working, I just didnt launch the correct app ..... 😅

Laravel, having a custom controller method with custom policy method?

I have a resource controller and want to add an extra custom policy method for destroyMany
In which I would check if the user is admin before deleting many.
The default methods work fine
Controller Method
Policy Method
index
viewAny
show
view
create
create
store
create
edit
update
update
update
destroy
delete
destroyMany
destroyMany
Controller destroyMany method is called, the policy isn't
Or should I stick to Gates for this extra method?
The docs say I can have any name for the methods and policies, How can both be linked?
destroyMany->destroyMany or
destroyMany->deleteMany would be a good setup.
And would be a great addition to my resource controller (where it should reside)
class ResourceController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
$this->authorizeResource(Resource::class, 'resource');
}
public function index()
{
return ResourceCollection::collection(Resource::all());
}
public function destroyMany(Request $request)
{
// gets called but needs a policy which isn't called
}
}
policy
class ResourcePolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
public function viewAny(User $user)
{
// works
return $user->hasAnyRoles(['admin', 'superAdmin']);
}
public function delete(User $user, Resource $resource)
{
// works
return $user->hasAnyRoles(['admin', 'superAdmin']);
}
public function deleteMany(User $user, Resource $resource)
{
// not called because the controller method needs to be hooked up, like the other methods
}
}
To get the addition policy method to work you will need to update the resourceAbilityMap for the controller. Adding the following to your controller should do the trick:
protected function resourceAbilityMap()
{
return array_merge(parent::resourceAbilityMap(), [
'destroyMany' => 'deleteMany'
]);
}
Also, if you don't return anything from your deleteMany policy method it will result in a 403.
If you're route/controller method isn't receiving an instance of the model then you will also need to update the array returned from the resourceMethodsWithoutModels method:
protected function resourceMethodsWithoutModels()
{
return array_merge(parent::resourceMethodsWithoutModels(), ['destroyMany']);
}

Laravel handle error that only thrown by controller

I am creating a logic where a controller can call another controller depend on Auth::user() role, but not all of controller shared same method, so i want if controller calling a method that does not exist it will throw a 404 not found.
here is my controller
class LokalController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
Public $controller;
public function __construct()
{
//$this->middleware('adminakses');
$this->middleware(function ($request, $next) {
$this->setController();
return $next($request);
});
}
public function setController()
{
$role = Auth::user()->role;
switch ($role)
{
case 'admin':
$this->controller = new \SIA\Http\Controllers\Admin\LokalController;
break;
case 'guru':
$this->controller = new \SIA\Http\Controllers\Guru\LokalController;
break;
case 'siswa':
$this->controller = new \SIA\Http\Controllers\Guru\LokalController;
break;
}
}
public function index()
{
return $this->controller->index();
}
for example Admin\LokalController has method A(), but Guru\LokalController doesn't, and if user logged in as guru and trying to cal method A() it should returning not found exception or something user understandable message, but currently showing BadMethodCallException method A() does not exist
The approach you're trying to work is achievable but I think it will be overwhelming in time.
public function index()
{
try {
$action = $this->controller . '#' . __FUNCTION__;
action($action);
} catch (Exception $e) {
abort('401', "Your Message");
}
}
How I'd do it instead is, I'd create a redirect path for the User model.
public function getRedirectPathAttribute() {
switch ($this->role) {
case 'admin':
return '/admin';
case 'guru':
return '/guru';
case 'siswa':
return '/siswa';
}
}
And then create a middleware to make the check, and if redirect is needed, I'd redirect using auth()->user()->redirect_path.
What do you think?
One option is to have a controller all this controllers inherits from that implement all methods by calling App::abort(404), and in each of the child classes implement the methods they need, stopping the methods in the parent classes from being called
class BaseController extends Controller{
public function a() {
App::abort(404);
}
}
class AdminController extends BaseController{
public function a() {
// to stuff for admin
}
}
Controllers inheriting from BaseController that don't implement a() will get 404, admin controller will not

Can authorize method in Request class return customized message for HandlesAuthorization trait?

I have the following code in Request class to check if the user is authorized to perform update.
HandlesAuthorization trait, by default gives default message. Is there any way to return customized message? I saw the authorize method in Request class can return boolean value only.
class UpdateRoleRequest extends Request
{
private $UserPermissionsSession;
public function __construct(IRole $Role) {
$this->UserPermissionsSession = new UserPermissionsSession();
}
public function authorize() {
$UserID = \Auth::user()->UserID;
return $this->UserPermissionsSession->CheckPermissionExists($UserID);
}
}
I believe you shouldn't look at HandlesAuthorization trait. All you need to do is implementing failedAuthorization method in your request class.
In FormRequest class it's defined like this:
/**
* Handle a failed authorization attempt.
*
* #return void
*
* #throws \Illuminate\Auth\Access\AuthorizationException
*/
protected function failedAuthorization()
{
throw new AuthorizationException('This action is unauthorized.');
}
so all you need is to override this method in your UpdateRoleRequest class for example like this:
protected function failedAuthorization()
{
throw new \Illuminate\Auth\Access\AuthorizationException('User has to be an admin.');
}
To provide a solution answering #Pooria Honarmand's question for anyone else wondering the same;
If you have more specific messages for different conditions that you already checked in the authorize method and you don't want to repeat those checks here, just introduce one or more class-based variables.
Here is one example having only one condition which does result in a non-standard message:
private bool $hasMissingClientId = false;
public function authorize(): bool
{
// several other checks
if (empty($user->client_id)) {
$this->hasMissingClientId = true;
return false;
}
return true;
}
protected function failedAuthorization()
{
if ($this->hasMissingClientId) {
throw new AuthorizationException('User has to be assigned to specific client.');
}
parent::failedAuthorization();
}

Laravel validation request class return model with errors

When validating a form with a request class you can manually validate the data using the validate() method but what do you return back I've tried return $this and return $this->errors but it just shows SQL integrity constraint duplicate entry which is correct but it doesn't show my form with the errors. When doing validation inside the controller you return the model and the errors but what do I return and set errors on validate method in the request class.
Request Class:
namespace App\Http\Requests;
use App\Http\Requests\Request;
use Auth;
class ProductRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
protected $action;
public function authorize()
{
if(Auth::check()) {
return true;
}
}
public function validate() {
$v = \Validator::make(parent::all(), $this->rules());
if ($v->passes()) return true;
$this->errors = $v->messages();
// tried returning $this; and $this->errors
return false;
}
public function all()
{
$data = parent::all();
if( $data['slug'] === '') {
// if the slug is blank, create one from title data
$data['slug'] = str_slug( $data['title'], '-' );
}
return $data;
}
public function messages()
{
}
public function rules() {
}
}
your rule method is empty your not validating any thing the error you got is an SQL exception not a validation error.

Resources