Laravel - Gates Multiple Or in middleware - laravel

I'm using laravel gates in my web.php, where i add middleware for can as follows
Route::post('/sellproducts', 'ProductController#Sell')->middleware('auth')->middleware('can:admin');
i want to add another rule for example can:admin or can:moderator so either of them is true, gate will allow
any ideas ?

I don't think you can use a logical or operator when enabling middleware for a route.
You could make a third Gate, that returns true when the user is either admin or moderator.
Another option is that you would create a ProductPolicy. In this policy you could create a sellProduct() method that checks if the user has the right roles:
public function sellProduct(User $user, Product $product)
{
// Return true when user is moderator or admin
}
You would have to call this method in your ProductController#Sell with:
$this->authorize('sellProduct', $product);
Take attention that gates and policies are meant to determine if a user is authorized to perform an action. This can be done by checking if the user has a certain role, or if the user is the owner of, in your case, a product. When you define a Gate as 'admin' things could get mixed up.

Route::post('/sellproducts', 'ProductController#Sell')->middleware('auth, can:admin');

Related

Laratrust middleware and blade directives to check from Profile not auth()->user()

I am getting to know the Laravel framework, and in the test application I am using the santigarcor/laratrust package to implement Roles and permissions.
For the project, I assumed that a user may have several profiles (One To Many) with assigned roles and permissions.
After logging in, the user is automatically assigned a default profile in the session, which he can change later.
For example:
User $user has a profiles: manager, editor and reader. Each profile has different roles/permissions.
The default profile is the editor. After logging in, I save to
Session::put('profile', $user->defaultProfile).
If I want to check the roles, e.g. in the controller, I can do:
$profile = Session::get('profile');
$profile->isAbleTo('edit-user');
But if i want to use middleware or blade directives #role(), #permission(), #ability() how to do it? best practice way?
Is it possible to easily map these methods so that they check not the user (auth()->user()) but his selected profile? Or I should write custom middleware and blade directives?
Since there was no answer here, I read a few and decided to use the built-in Gate functionality. So I can use Gate methods for authorizing abilities (allows, denies, check, any, none, authorize, can, cannot) and the authorization Blade directives (#can, #cannot, #canany).
The gates are defined dynamically:
\App\Models\Permission::get()->map(function($permission) {
Gate::define($permission->name, function($user) use ($permission) {
if (session()->has('profile')) {
$profile = session()->get('profile');
return optional($profile)->hasPermission($permission->name);
}
return false;
});
});
So for now I think is solved, but I will test it more.

Laravel menu based on role?

i have codeigniter background. Now, i'm learning about laravel. So, i'm in this condition (Example), I'm trying to create a webapp, which has multiple users. The UsersType A , they can access menu a, menu b & menu c and UsersType B they only can access Menu a.
Now, i'm using https://github.com/lavary/laravel-menu . Well, if it's only have two types , i can write it manually. But, what if there are five types of user or more.
When i'm using codeigniter. I create 4 table Users , UsersType , Menu & MenuAccess. You must be understand how it's work. I just, play it with query then i show it.
UsersType (Users) -> TypeId (UsersType) -> MenuId (MenuAccess) -> MenuId (Menu)
I already use google and I found this https://github.com/Zizaco/entrust but what i can see from that package. It's only give the permission on the action (input,edit & delete)
So, Can i do my codeigniter way in my laravel ? Save my routes properties than show it in my rouotes/web.php (I don't know if it possible, haven't try it yet). sorry for my english.
What I would do is put a function in the User class which checks it's own permission and then returns a view which contains the menu that user has access to.
public function menu()
{
switch($this->role) {
case 'admin':
return view('menus.admin');
[etc]
}
}
Then in the view just check if the user is logged in and show the menu:
#if Auth::check()
{{ Auth::user->menu() }}
#endif
As mentioned in the comments,it sounds like what you want is the ability to conditionally display content based on whether a user has certain permissions.
There's a number of implementations of this. Essentially what they all do is store permissions that can be granted to users, and optionally store roles that allow permissions to be assigned to a role and then users can be given that role, automatically granting them the permissions associated with that role.
I've found spatie/laravel-permission which appears to be quite good. Then, if you pass your user model into the view, you can do something like this:
#if ($user->can('edit-posts'))
<a>Edit post</a>
#endif
That should be flexible enough that it can be reused for different permissions too. If that doesn't do the trick, then it's not hard to roll your own permission system using Laravel's authorization system and you should be able to use the can() method in the same way.

Restrict access | change template or redirect based on user role

I have AdminLTE on laravel application and when admin user logins through AdminLte login screen, he logins to admin panel and accesses its pages. It's ok, when he opens frontend website, admin name shows on the header (as shown on below image) as he logins previously through admin login screen.
What I want he must not be login on front site pages. (The following should appear on the header as shown on below image).
He needs to login separately on front site. What's the solution for that.
ok so you have to make if and else on app.blade.php from where your menu is generated.
#if (!Auth::guest())
#include('admin.includes.normal_header')
#endif
You need to make two middleware, one is admin middleware, another one is for normal login user.
In normal middleware, you can check if the user is logged in as an admin or not.if logged as an admin in then logged out him.
There are several ways to overcome this:
you can use different guards and middleware( using separate table for admin and user)
you can use role based permission( if you use users table for both types of user)
Step - 1: create a roles table ( cols: id, role ) and a Role.php Model
Step - 2: add a column named 'role_id' at your user table
Step - 3: make a relationship for role and user on your User.php model
user belongs to a role
// Assuming that you have 2 roles: 1->Admin, 2->User
public function role(){
return $this->belongsTo(Role::class);
}
step-3: in you nav, use the if else condition
#if (!Auth::guest())
#if(auth()->user()->role()->id == 1)
#include('admin.admin_header_nav')
#else
#include('user.normal_header_nav')
#endif
#endif
// you can just use those condition on a link, or create a middleware
//called admin to wrap up the condition( auth()->user()->role()->id == 1 ),
// leaving it up to you

Allow CRUD only to Auth::user that owns the ressource

I currently work on a project where the User creates Models, that only he/she is allowed to see, edit or delete.
The Create Part done by Eloquent Relationships, but for the other operations I would like to combine it with Route Model binding and not manually in the controller. I tried solving it with middlewares, but I couldn't access the Ressource.
Can somebody point me to the right Direction, any best Practices are welcome!
Personally I use route model binding, but only allow the model to bind if the user owns the record.
This means that no matter what - people can never access someone elses record. So for example, in my route I can do
$router->get('property/{property}, ['uses' => PropertyController#show]);
Then in my RouteServiceProvider:
$router->bind('property', function($value) {
$property = \App\Property::findOrFail($value);
if ((int)$property->user_id !== (int)auth()->id()) {
abort (404);
}
return $property;
});
So in the example above - we have a property route, and it will try and find the property record given. It will then check that the user owns the record, otherwise it throws a 404 (but you could just redirect or something - up to you).

Extending ion auth to only allow registrations from certain email addresses/domains

I want to extend Ion Auth to only allow certain email addresses to register.
I'm fairly sure I could hack this together and get something working, but as a newbie to codeigniter and ion auth I wish to find out if there is a "proper way" to be doing what I need?
For instance can I "extend" ion auth (so I can update ion auth core files without writing over my changes?).
I noticed there are also hooks including this one (in the register function):
$this->ci->ion_auth_model->trigger_events('pre_account_creation');
Where do these resolve and can I use this one in order to intercept registrations from email addresses which don't match a list of those I wish to register?
If so, how would I do it? I would need access to the $email variable from the register() function.
Or is it just a case of altering the base code from ion auth and not updating it in the future?
Thanks for any help you can give me. Don't worry about the email bit, I'm capable of working out whether an email address matches the required email domains, I'm more interested in what is the best way to go about extending the library.
Tom
EDIT: Hi Ben, thanks for your answer, and thanks for taking the time to have a look at my issue. Unfortunately this hasn't helped.
I guess what you're trying to do there is add a little bit to the sql query a "where in" clause? I guess that the where in bit is incorrect as there isn't a column name.
Also, at this point I can't modify the sql query satisfactorily to produce the required output. e.g. I can add a hook to a function which is literally $this->db->where('1=1') and this outputs this sql in the next query:
SELECT COUNT(*) AS `numrows` FROM (`users`) WHERE `1=1` AND `email` = 'rawr#rawr.com'
The AND email = 'rawr#rawr.com' bit will always still return no rows. It should be OR email = 'rawr#rawr.com', but without editing the Ion Auth core code then I won't be able to change this.
I am starting to suspect (from the last couple of hours of tinkering) that I may have to edit the ion auth core in order to achieve this.
Check out this example: https://gist.github.com/2881995
In the end I just wrote a little form_verification callback function which I put in the auth controller of ion_auth which checked through a list of allowed domains. :)
When you validate your form in the auth controller you add a callback:
$this->form_validation->set_rules('email', 'Email Address', required|callback_validate_email');
You create a method in the controller called validate_email:
function validate_email() {
if (strpos($this->input->post('email'), '#mycompany.com') === false) {
$this->form_validation->set_message('validate_email', 'Not official company email address.');
return false;
} else return true;
}
This will cause the creation of the user to fail, since all rules must pass. You also provide an error message. Just make sure to have this line on the form view side:
echo validation_errors();

Resources