I'm developing a Laravel ACL System. In my ACL I'm grant the permissions via HasPermission Middleware, in my middleware can't check any permission it's always executed the redirect()->back() method.
Here is my code Sample.
class HasPermission
{
public function handle($request, Closure $next,...$permissions)
{
// $permissions = explode(',', $permissions);
//dd($permissions);
foreach($permissions as $permission){
if (Auth::user()->can($permission)) {
return $next($request);
}
}
return redirect()->back();
}
}
My Controller.
function __construct()
{
$this->middleware('auth');
$this->middleware('HasPermission:Role-Read,Role-Delete')->only('userEdit');
$this->middleware('can:Role-Update')->only('userEdit');
}
This. Auth::user()->can($permission) is not work properly. What will be the solutions for this problems.
try:
Auth::user()->can('field you want to update',$permission);
Related
I implemented passport authentication in Laravel and the basic auth.
I have UserController and inside it, I have the constructor methode:
public function __construct()
{
$this->middleware('auth.basic.once')->except(['index', 'show']);
$this->middleware('auth:api')->except(['index', 'show']);
}
The OnceBasic middleware:
public function handle($request, Closure $next)
{
if(Auth::guard('api')->check())
return $next($request);
else
return Auth::onceBasic() ?: $next($request);
}
In the OnceBasic middleware, I'm able to check if the user authenticated using the auth:api then I prevent the authentication from trying to use the onceBasic, So it worked correctly when using the access token. But it fails when trying to authenticate using the onceBasic(email, password) because the auth:api trying to authenticate too and it fails(trying to call the redirectTo() methods inside the default \App\Http\Middleware\Authenticate.php )
My question is there a way to use both of these middlewares, to only successfully authenticate one and prevent the other from working?
My approach to using the same controller for two guards required pointing two separate groups of routes to the controllers. I provided an example in this answer to a similar question, here is the example code again:
<?php
Route::middleware(['auth:admin_api'])->group(function () {
Route::prefix('admin')->group(function () {
Route::name('api.admin.')->group(function () {
////////////////////////////////////////////////////////////
/// PLACE ADMIN API ROUTES HERE ////////////////////////////
////////////////////////////////////////////////////////////
Route::apiResource('test','App\Http\Controllers\API\MyController');
////////////////////////////////////////////////////////////
});
});
});
Route::middleware(['auth:api'])->group(function () {
Route::name('api.')->group(function () {
////////////////////////////////////////////////////////////
/// PLACE PUBLIC API ROUTES HERE ///////////////////////////
////////////////////////////////////////////////////////////
Route::apiResource('test', 'App\Http\Controllers\API\MyController');
////////////////////////////////////////////////////////////
});
});
So when an admin user goes to admin/test, it uses the admin auth guard, and when a normal user goes to /test it uses the standard auth guard. Both of these use the same controller.
I then created a base controller for my app. Here is how I determined with guard is being used to access the route in the constructor:
<?php
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
class BaseController extends Controller
{
protected $user;
protected $isAdmin = false;
public function __construct()
{
if(Auth::guard('admin_api')->check()) {
$this->user = Auth::guard('admin_api')->user();
$this->isAdmin = true;
} elseif(Auth::guard('api')->check()) {
$this->user = Auth::guard('api')->user();
$this->isAdmin = false;
} else {
return response()->json([
'message' => 'Not Authorized',
], 401);
}
}
i'm trying to create a website based on laravel framework. I'm stuck in permission control with Policy. This is my code:
+ Policies Register in App\Providers\AuthServiceProvider:
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
User::class => UserPolicy::class,
Category::class => CategoryPolicy::class
];
public function boot()
{
$this->registerPolicies();
try {
Permission::all()->each(function($permission) {
Gate::define($permission->name, function ($user) use($permission) {
return $user->hasPermission($permission->name);
});
});
} catch (\Exception $e) {
Log::notice('Unable to register gates. Either no database connection or no permissions table exists.');
}
}
}
User Policy in App\Policies\UserPolicy
class UserPolicy
{
use HandlesAuthorization;
public function viewAny(User $user)
{
return true;
}
public function view(User $user, User $target_user)
{
return $user->id === $target_user->id;
}
}
Api Route in routes/api.php
Route::get('/users', 'Api\UserController#getUsers')->middleware('can:view-users');
Route::get('/users/{user_id}', 'Api\UserController#getUser')->middleware('can:view-users');
Route::put('/users/{user_id}', 'Api\UserController#updateUser')->middleware('can:edit-users');
User Controller in App\Http\Controllers\Api\UserController
public function getUsers(UserRequest $request) {
$users = $this->userRepository->getAll();
$this->authorize('view', $user);
return response($users, 200);
}
public function getUser(UserRequest $request, $user_id) {
$user = $this->userRepository->find($user_id);
$this->authorize('view', $user);
return response($user, 200);
}
When I try to get data by using 2 url above, it returned error 500 Internal Server Error even when user is authenticated :
{
"error": "This action is unauthorized."
}
I tried to log result and found that error come from middleware can or Illuminate\Auth\Middleware\Authorize.
Code line:
$this->gate->authorize($ability, $this->getGateArguments($request, $models)); in handle() function throw error above.
After hours searching, I could not figure out solution.
Anyone can point out my mistake?
Solved. After hours reading source code in library, I figured out problem. I used api guard for my app without passport module. Thus, variable $userResolver in Illuminate\Auth\Access\Gate class could not be set to authenticated user and got null value. To solve this problem, I created my own Authorize middleware instead of laravel middleware Authorize and use Auth::guard('api')->user() to get authenticated user.
I'm trying to implement roles and permissions for my laravel API. I installed the package:
https://yajrabox.com/docs/laravel-acl/3.0/introduction
It would be great if someone could explain to me how it works, all I want to do is get the permission when the user hits one API route.
I don't want to set the middleware in every route, because I'm going to do several routes and it would be a pain to set middleware every time, I want do it dynamically.
I tried to do it myself but it's not working. This is my code in Authserviceprovider:
public function boot(GateContract $gate)
{
$this->registerPolicies();
Passport::routes();
Passport::tokensExpireIn(Carbon::now()->addDays(15));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
$permissions = Permission::with('roles')->get();
foreach ($permissions as $permission)
{
$gate->define($permission->name, function (User $user) use ($permission) {
return $user->hasPermission($permission);
});
}
}
I'm doing like this: https://github.com/laracasts/laravel-5-roles-and-permissions-demo/tree/master/app
You can use middleware within your web.php / api.php file such as my example (web.php) below:
Route::group(['middleware' => ['verified']], function () {
Route::get('/', 'HomeController#index')->name('home');
});
As my example shows, this will check an account is verified before allowing it to view '/'
Updated
This is almost irrelevant to the question above but as the Op asked a secondary question within the comments to my answer: here is my middleware code to show the Op how the middleware will function:
public function handle($request, Closure $next)
{
$verified = Auth::user();
if ($verified->verified == 0)
{
Auth::logout();
Session::flash('error', "$verified->username, your email address hasn't been verified yet therefore you're unable sign in.");
return Redirect('/login');
}
return $next($request);
}
I used Gate for laravel authorization where A user have One role and one role have Multiple Permissions. I used the following method for checking role has permission or not. But it doesn't work properly means user may have chance to access one route though I have given him multiple permissions through roles.
See the scenario is suppose admin can see list of users as well can access test route. But in my case admin can see list of users but he can't access the test route. Though I have given him the access in permission table.
Can anyone suggest what's the problem here?
public function boot(GateContract $gate)
{
$this->registerPolicies();
foreach ($this->getPermissions() as $permission) {
$gate->define($permission->name, function ($user) use ($permission) {
return $user->role->id === $permission->role_id;
});
}
}
public function getPermissions()
{
return Permission::with('role')->get();
}
In controller Code :
public function test(){
if(Gate::allows('test')){
echo "This is Test";
}
return redirect('/');
}
I am using multiple views for the same URL, depending if the user is logged in or not.. so mywebsite.com is routed like this:
Route::get('/', 'HomeController#redirector')->name('home');
The controller is this:
public function redirector(){
if(!\Auth::check()){
return view('welcome');
}
else{
return $this->index();
}
}
Now, when it runs the index function I need it to run the middleware 'auth', that updates and checks the user. The problem is, I cannot attach it to the route, since they might be unlogged causing a redirection loop. I tried this:
public function redirector(){
if(!\Auth::check()){
return view('welcome');
}
else{
$this->middleware('auth');
return $this->index();
}
}
It does not run the middleware.
If I put it in the costructor method attaching it to index, like this:
$this->middleware('auth', ['only' => 'index'])
it also won't run.
Any solutions to this?
if(!\Auth::check()){..} //this returns false if a user is logged in, are you sure that's what you want?
If not then remove the '!'
You can also put the redirection logic in the middleware instead. If you are using the auth middleware that ships with Laravel this is already in place. You just have to modify it as below and place the middleware call in the constructor.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
return redirect()->guest('login');
}
return $next($request);
}