I have update method like this
public function update(Contact $contact)
{
$this->authorize('ownItems', $contact);
......
}
and ContactPolicy :
public function ownItem(User $user,Contact $contact)
{
return true;
}
It work correctly but when I replace Contcact to ContactRequest in my update method
show me this :
403 This action is unauthorized.
update method :
public function update(ContactRequest $contact)
{
$this->authorize('ownItems', $contact);
.......
}
authorize method in ContactRequest:
public function authorize()
{
return true;
}
ContactRequest is a laravel Request class instance
public function update(ContactRequest $request,Contact $contact)
{
$this->authorize('ownItems', $contact);
.......
}
You misspelled method name in $this->authorize('ownItems', $contact);, it should be "ownItem"
UPD
ContactRequest is probably instance of Illuminate\Http\Request but authorize method waiting for Model instance, if you do not have model identifier in yout request. first you should to find model: $model = Contact::find($contact->input('id')) and than check your policy with $this->authorize('ownItems', $model)
Related
I have a method that accepts a request
public function createUser(Request $request)
{
...
}
I want to call it from another method
public function someMethod(){
$array = [...];
return $this->createUser($array); <----
}
and how can I pass a new request to it with the array I need?
How about instead of trying to call a controller method, you move the logic to create a user to a service class and then use the service class in your createUser and someMethod methods?
UserService.php
class UserService
{
public function __construct() { }
public function createUser(array $userData)
{
// TODO use $userData to create a user here
return $newUser;
}
}
SomeController.php
public function createUser(Request $request)
{
$this->userService->createUser($request->all());
}
public function someMethod(){
$array = [...];
return $this->userService->createUser($array);
}
I have update and store method like this
public function update(ContactRequest $request)
{
if (Auth::user()->can('edit_contact'))
$request->update();
else
return $this->accessDenied();
}
public function store(ContactRequest $request)
{
if (Auth::user()->can('add_contact'))
$request->store();
else
return $this->accessDenied();
}
and authorize in FormRequest class
public function authorize()
{
return \Gate::allows('test', $this->route('contact'));
}
I want to pass permission name to authorize method like this:
public function authorize($permissionName)
{
if (Auth::user()->can($permissionName))
return \Gate::allows('test', $this->route('contact'));
}
and in controller like this
public function update(ContactRequest $request)
{
$request->update('edit_contact');
}
public function store(ContactRequest $request)
{
$request->store('add_contact');
}
You have 3 options:
Change your authorization method to this:
public function authorize()
{
return $this->user()->can(
$this->route()->getActionMethod() === 'store'
? 'add_contact'
: 'edit_contact'
)
&& \Gate::allows('test', $this->route('contact'));
}
Make your authorize method of request return true and check authorization by defining another gate an call it on your controller:
public function authorize()
{
return true;
}
Gate::define('modify_contact', function ($user, $permissionName) {
return $user->can($permissionName)
&& $user->can('test', $request->route('contact'));
});
public function update(ContactRequest $request)
{
Gate::authorize('modify_contact', 'edit_contact');
//...
}
public function store(ContactRequest $request)
{
Gate::authorize('modify_contact', 'add_contact');
//...
}
Define and use policy the same way and pass your arguments to it.
There is no direct way of passing argument to authorize method of form request, but you can do the implementation this way:
public function authorize()
{
$method = Request::method();
if($method == 'post') {
$permission = 'add_contact';
} elseif($method == 'put') {
$permission = 'edit_contact';
}
if (Auth::user()->can($permission))
return \Gate::allows('test', $this->route('contact'));
}
If you are using laravel's default post, put routes then this will help you out.
It is better to make two different Requests for store and update, anyway you need to check some values depended on action.
So you can user default laravel's policy approach for Resource controllers and not use Request::authorize for authorization logic.
Laravel policy controller helpers
I'm trying to delete a user account using laravel query builder so I'm doing this
AuthRepository
class AuthRepository implements IAuthRepository
{
....
public function delete($user_id)
{
$res = User::where('id', $user_id->id)->delete();;
if ($res) {
return response('Success, user was deleted', 204);
} else {
return response()->json(error);
}
}
}
In controller
class AuthController extends Controller
{
protected $auth;
public function delete($user_id)
{
return $user_id->delete();
}
}
in api.php
Route::group(['prefix' => 'auth'], function () {
Route::group(['middleware' => 'auth:api'], function () {
// Delete user
Route::post('user/delete/{user_id}', 'AuthController#delete');
});
});
Passing user_id to ${API_URL}/auth/user/delete/{user_id} I'm facing
Call to a member function delete() in Controller on line return $user_id->delete();. Can someone please explain me why is this happening, thanks.
Take advantage of the route model binding and to this instead:
public function delete(User $user)
{
return $user->delete();
}
And your route:
Route::post('user/delete/{user}', 'AuthController#delete');
You cannot call delete() on an integer.
If you don't want to use the Route model binding as suggested by #nakov and insist on using id then you have to get the user first before deleting.
public function delete($user_id)
{
$user = User::findOrFail($user_id);
return $user->delete();
}
I have a table sites with list of sites with following columns ('id', 'path', 'site_link'). I've written in a Site model public $timestamps = false; so that it won't try to work with time what I don't need.
Also I have the following routes
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', function ($api) {
$api->get('sites', 'App\Http\Controllers\SiteController#index');
$api->get('sites/{site}', 'App\Http\Controllers\SiteController#show');
});
The first one is working fine and returning all the data, however the second one is returning just [].
I have a controller which is below
namespace App\Http\Controllers;
use Illuminate\Http\Request;
Use App\Site;
class SiteController extends Controller
{
public function index()
{
return Site::all();
}
public function show(Site $site)
{
return Site::findOrFail($site);
}
public function store(Request $request)
{
$site = Site::create($request->all());
return response()->json($site, 201);
}
public function update(Request $request, Site $site)
{
$site->update($request->all());
return response()->json($site, 200);
}
public function delete(Site $site)
{
$site->delete();
return response()->json(null, 204);
}
}
The show method in your SiteController is taking a Site object. However the route is set up to only take the siteId. The code below should work for you based on how you've set up your routes.
public function show($site)
{
return Site::findOrFail($site);
}
Apply same to all your other controller methods since you want pass the site id via the url to the controller methods.
I am seeing some behaviour. I can't explain when accessing user data via the Auth facade in Laravel class. Here's an extract of my code:
private $data;
private $userID;//Set property
function __construct()
{
$this->middleware('auth');//Call middleware
$this->userID = Auth::id();//Define property as user ID
}
public function index() {
return view('');
}
public function MyTestMethod() {
echo $this->userID;//This returns null
echo Auth::id();//This works & returns the current user ID
}
I am logged in and have included use Illuminate\Support\Facades\Auth; in the class thus the code works, but only when accessing Auth in methods - else it returns a null value.
Most odd, I can't work out what is causing this. Any thoughts much appreciated as ever. Thanks in advance!
In Laravel Laravel 5.3.4 or above, you can't access the session or authenticated user in your controller's constructor, since the middlware isn't runnig yet.
As an alternative, you may define a Closure based middleware directly in your controller's constructor.:
try this :
function __construct()
{
$this->middleware(function ($request, $next) {
if (!auth()->check()) {
return redirect('/login');
}
$this->userID = auth()->id(); // or auth()->user()->id
return $next($request);
});
}
another alternative solution go you your base controller class and add __get function like this :
class Controller
{
public function __get(string $name)
{
if($name === 'user'){
return Auth::user();
}
return null;
}
}
and now if your current controller you can use it like this $this->user:
class YourController extends Controller
{
public function MyTestMethod() {
echo $this->user;
}
}
You should try this :
function __construct() {
$this->userID = Auth::user()?Auth::user()->id:null;
}
OR
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->userID = Auth::user()->id;
return $next($request);
});
}