I'm using Laravel 5.1's authorization features, documented here. My controllers implement AuthorizesRequests and I have my policies set up connecting policies to their models to create an ACL of sorts. In my controllers, I'm checking for authorization in each method. For example, in an 'AgencyController' the 'update' method calls $this->authorize($agency), which then checks my AgencyPolicy's update method to know rather or not the current user is allowed to update the agency, just as described in the documentation. This works the way I want it to.
However, what I can't seem to figure out is how to use authorization for other methods like index() and create() where there isn't a specific model being used. Calling $this->authorize('index') seems to return false, even if I have an index($user) function in my policy class that only returns true.
I'm new to using Laravel's authorization helpers, so I might be going about this wrong or missing something obvious. Any help pointing me in the right direction would be gretaly appreciated!
You have to pass it the class name of the model you're checking:
$this->authorize('index', Agency::class);
With some help from someone in the Laravel slack group I was able to find the answer to this myself.
Without an instance of the model, the authorize() calls couldn't map to the correct policies. But by simply passing the class to them, it is able to and works.
For example, instead of calling $this->authorize('index') in my controller's index method, I'm now calling $this->authorize('index', Agency::class) to give it the correct model to use.
Related
I'm developing a Laravel 5 package where I have a "Member" model which currently extends App\User model. I would like to know the best practice to let any developer use a custom "Member" model instead of the one from the package. This is for example to allow a developer use another table.
One approach that seems to work without having done a deep test with it is to make an alias in my package service provider in the register() method:
$MemberModel = 'MyVendor\MyPackage\Member';
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('MyMember', $MemberModel);
In this case I have to:
Replace all entries in the code from the original class to the alias
Delete all php "use" entries related to it
Get the value of $MemberModel from a config file or the database
But I don't know if it is a good way to solve it or It may cause any conflict.
Is there any other and better approach for this goal? Thanks in advance!
I finally had to test by myself this approach without haven't read the solution anywhere else, but anyway everything seems to work fine in my source code.
If anyone is looking for doing anything similar, the code example in my question works because the $MemberModel is defined with a value. If you want to get that value from a Model instance, as me, you have to add that code in the boot() method of the service provider.
I have a problem when using user model's can and cannot method. I have a post model and an user model. And I define an add method in PostPolicy class:
public function add(User $user){
if($user->isGuest()) return false;
return true;
}
I know when use can or cannot method, the policy class which will be used will be resolved automatically by model instance we pass to can or cannot method, like $user->can('update',$post). But in this example. the add method does not need a post instance, So I can't do like this $user->can('add',$post). Can someone tell me how to get done it?
It's a good question.
The funny thing is this isn't documented for Laravel 5.2 but it is for 5.4. So you will have to check if this works for you in Laravel 5.2.
When you don't have an object model to pass into the policy check the documentation says you should pass this instead Model::class. In your case, it'd be Post::class as the parameter. So it'd be:
$user->can('update', Post::class);
If this does not work for you in Laravel 5.2 you can always write a Gate instead of a policy and just use the Gate::allows() or Gate::denies methods:
https://laravel.com/docs/5.2/authorization#gates
I need to authorize users on a forum.
So in blade, I have #can('editPost', $post) before showing the form to reply to a topic. My PostPolicy class has a editPost method that validates to true if it's the users own post.
However, the issue appears when I want to do a simple check, like deletePost(). This checks to see if Auth::user()->isAdmin
public function deletePost(User $user) {
return Auth::user()->isAdmin;
// return $user->isAdmin
}
However, this won't even get called, since I'm not passing an instance of Post
My real world application is much more complicated, but I'm using isAdmin as a simple example.
I guess defining $gate->define('deletePost', 'App\Policies\PostPolicy#deletePost'); in AuthServiceProvider could work, but would end up separating my definitions and methods, and ultimately for a large app clutter the AuthServiceProvider
When you register a policy it is the classname that is used to route checks to the class, so in order to get routed to the policy you can just pass the class name of the type you registered it with.
Try using #can('delete', Post::class) and see if that gets you there
refer to
Illuminate\Auth\Access\Gate::firstArgumentCorrespondsToPolicy
EDIT
After a little more diggin I found this
https://github.com/laravel/framework/commit/70f75255808ffc96275e6f2f356616dd2e163434#diff-961368895033e553787b301c3be0e17a
so it looks like if you on version 5.1.23 then you will be able to pass a string otherwise your will need to just pass new Post
In controllers
$this->authorize('<ability>', <Class-With-Rule::class> | <Full-Path-To-Class>);
In Blade view
#can('<ability>', <Class-With-Rule>::class> | <Full-Path-To-Class>)
In Eloquent model
$user->can('<ability>', <Class-With-Rule>::class> | <Full-Path-To-Class>);
Methods Without Models:
Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing create actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all.
When defining policy methods that will not receive a model instance, such as a create method, it will not receive a model instance. Instead, you should define the method as only expecting the authenticated user:
https://laravel.com/docs/7.x/authorization
Is it possible to call directly from a model method from another model of the same component?
Is there any default Joomla option to call in such a way.
Yes You can
It will not break MVC architecture,
You can check like this
if(!class_exists('VirtueMartModelUser')) require(JPATH_VM_ADMINISTRATOR.DS.'models'.DS.'user.php');
$usermodel = VmModel::getModel('user');
$currentVMuser = $usermodel->getUser();
First you should include the model file in the required model then create the object.
then call like above.
This example is Virtue-mart using method
According to the my knowledge NO. Otherwise it will break the MVC architecture.
What you can do is
Replicate the function you want to use.
Make the call from the controller to the both method.
My Advice is to you is even if you figure out a way to do it, Don't do it. It will mess up your whole architecture.
If you have any issues please ask.
The text is quite long, the question is actually simple and written in bold. The other text is only for trying to explain the problem.
I have recently started to use CodeIgniter for developing my website. Currently, I'm writing a side menu where you can filter the items showed in the view (basic e-commerce functionality).
The idea I had was to have an array in my Shop-controller where I store my filtering values which are passed to and from my filterview, so the filter menu kan handle several types of filters.
The problem is that it seems like the constructor of the controller is run each time the controller is called. I thought that the controller was constructed only once when the user enters the website. I'm pretty new at website devlopment and am mainly a C++-guy, so this seems a bit strange for me.
My question is pretty simple actually: Is it true that the controller instance is created at each call to a controller function? Otherwise, what am I doing wrong to cause the controller instance to be reinstantiated at each controller call...
I hope that my question is not too fuzzy. It is important for me to understand the lifecycle behaviour of CodeIgniter to be able to find a simple solution for this. I would like to avoid using $_SESSION, because I would like to use a OOP like solution.
Is it true that the controller
instance is created at each call to a
controller function? Otherwise, what
am I doing wrong to cause the
controller instance to be
reinstantiated at each controller
call..
Yes, the controller instance is re-instantiated every time you make a call to that controller. In CodeIgniter, there is no such thing as a persistent instance of your controller for each user interacting with your application (unlike single-user apps built in C++). What you do have is session management, where you use Session variables to store data persistent to that particular session between the user's browser and your web server (more). Another way to do this is by using cookies. I personally prefer session over cookies.
There is no harm in using $_SESSION for the purpose of your filter, and it is not against OOP principles. What matters is how you use the data stored in your Session variable once your controller instance has loaded ( that's where the OOP concepts come into play).
Shivaas, the same answer can by safely used with models? What about autoloading models? I mean, autoloading it's just a way to avoid typing $this->load->model('the_model') when needed? There's no way to use singleton pattern without recurring to use session/database?
private $instance;
function init_model() {
if ($this->instance === NULL) {
$this->instance = array();
}
return $this->instance;
}
Once init_model exits, the class instance is destroyed so $instance will be always initialized to a new array()?