Laravel multi auth protecting route multple middleware not working - laravel

I have created an extra middleware admin and I want to protect my routes. Adding one single middleware 'auth' or 'auth:admin' is working.
Route::get('/calendar', function () {
return view('app', ['data' => []);
})->middleware('auth');
But I want that as an admin you can also access the user routes but this is not working. If I try the following, and I log in as an admin I get redirected to the login page all the time.
Route::get('/information', ['middleware' => ['auth', 'auth:admin'], function () {
return view('app', ['data' => ['auth' => Auth::check()]]);
}]);
But if I change ['auth', 'auth:admin'] to ['auth:admin','auth'] it is working for admin but not for user. So it seems that only the first element of my middleware in array is being recognized. Does anybody have any idea why my multiple middlewares are working seperate but not together? Any help is appreciated

If you are trying to allow multiple 'guards' to be checked for a route you can pass multiple guards as parameters to the Authenticate middleware, auth.
auth:web,admin (assuming web is your default guard).
This will try to resolve a user (Authenticatable) from each guard passed in. If any guard returns a user (Authenticatable) you pass through authenticated. If not you are a guest.
If you set the middleware auth and auth:admin those are 2 separate 'middleware' in the stack that are unrelated.

Route::get('/information', ['middleware' => ['auth', 'auth:admin'],function () {
return view('app', ['data' => ['auth' => Auth::check()]]);
}]);
in this code. ['auth', 'auth:admin'] that's mean you need to login default guard and admin guard. if you need only login admin guard, ['auth:admin']

Related

How to set role name in prefix dynamically for same route group in laravel

I want to create dynamic prefix name according to logged user role name like for a same route group
if admin is login in admin panel then
url like :
http://localhost:8000/admin/dashboard
And, if dealer is login in admin panel :
http://localhost:8000/dealer/dashboard
my route group is
Route::group(['prefix' => 'admin', 'as' => 'admin.', 'namespace' => 'Admin', 'middleware' => ['auth', 'verified', 'preventBackHistory']], function () {
Route::get('/dashboard', 'HomeController#index')->name('home');
});
Basically My route group is same for admin & dealer
when i want different prefix according to user role when user is successfully login
It is a normal php file, so you may just add
if(...){ // if admin
$prefix = 'admin';
}else{ // if dealer
$prefix = 'dealer';
}
before your routes, and in your routes:
Route::group(['prefix' => $prefix, 'as' => $prefix.'.', 'namespace' => ucwords($prefix), 'middleware' => ['auth', 'verified', 'preventBackHistory']], function () {
Route::get('/dashboard', 'HomeController#index')->name('home');
});
Note: This is making a few assumptions about what you are doing.
You are not going to have access to the information about the current user until after the routes have been registered. The session has not started until after the request has been dispatched to a route and passes through the Middleware stack which will start the session. This is an idea of how to achieve that in a way that makes sense for the order of events.
You should setup the route group with a dynamic prefix:
Route::group(['prefix' => '{roleBased}', 'as' => 'admin.', 'namespace' => 'Admin', 'middleware' => ['auth', 'verified', 'dealWithPrefix', 'preventBackHistory']], function () {
Route::get('/dashboard', 'HomeController#index')->name('home');
});
Then in the RouteServiceProvider you will be adding a constraint for the prefix, parameter roleBased, to only allow it to be admin or client:
public function boot()
{
// restrict the prefix to only be 'admin' or 'dealer'
\Route::pattern('roleBased', 'admin|dealer');
parent::boot();
}
Now you will have to create a middleware to deal with getting the information of the current user to set a default for this prefix so that any URLs you generate to these routes will have this prefix and you don't have to pass a parameter for it. We will also remove the prefix parameter from the route so it does not get passed to your actions:
public function handle($request, $next)
{
$role = $request->user()->role; // hopefully 'admin' | 'client'
// setting the default for this parameter for the current user's role
\URL::defaults([
'roleBased' => $role
]);
// to stop the router from passing this parameter to the actions
$request->route()->forgetParameter('roleBased');
return $next($request);
}
Register this middleware in your kernel as dealWithPrefix. Note in the route group above this middleware was added to the list of middleware.
If you need to generate URLs to any routes in that group, and the current request isn't one of the routes in that group, you will be required to pass a parameter for this prefix when generating the URL:
route('admin.home', ['roleBased' => ...]);
If the request is currently for one of the routes in that group you will not need to add this parameter:
route('admin.home');
Note: This middleware could be applied in a wider way but you would need to know what default you want to use for this parameter if someone wasn't logged in. This is also assuming you may have more than just 1 route in that route group. If it is only that one single route then this can probably be adjusted slightly.

How to chose guard for session driver

I'm trying to create a login page with laravel web route. When user login, a session record will be saved to database. But in session table, user_id always get null value.
I've found that in Illuminate\Session\DatabaseSessionHandler, function userId() always return null. It's because I set default guard for api. This is my config/auth.php:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
When I change default guard to web, column user_id in database has value is authorized user id. I don't want to change my default guard to web.
How can I set guard driver for session? Is there something like Auth, we can use Auth::guard('web').
Thanks
Typically, API's are not associated with keeping session state between requests.
You can always add additional groups with seperate guards to the same routes and use them according to your needs. E.g.
Route::group(['middleware' => 'auth:api'], function () {
Route::post('/user', 'UserController#apiUser');
}
Route::group(['middleware' => 'auth'], function () {
Route::post('/user', 'UserController#index');
}
and then seperately reference
$user = auth('web')->user();
or
$user = auth('api')->user();
Read here for a Laravel API implementation using Passport. You may also want to consider Laravel Sanctum which offers support for API token generation for your users.

Laravel passport public api routes

I am trying to code a login function for my api that takes a username and password then give you a password grant token to make api requests. The login route when called gives you
{
"message": "Unauthenticated."
}
I am using passport on laravel to do secure the api. Why am I getting a 401 when the route does not have the auth:api middleware? I tried using a clousure to see if I get could get a response and the closure did not give me an error.
Route::group(['prefix' => '/v1', 'middleware' => ['auth:api'], 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::post('/post/like','PostLikeController#store');
});
Route::group(['prefix' => '/v1', 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::post('login', 'Auth\LoginController#login');
});
Does your login controller have a constructor? sometimes middleware is set in there?
Otherwise I've also had issues with having the middleware routes above the public ones.
Try putting the public routes in the file first and also checking the LoginController.php for a constructor which might be setting a middleware
It possibly due to the same prefixes, as it does not overriding but instead stacking on top of each other.
I suggest for your login route, possibly, you can use this
Route::post('login', 'Auth\LoginController#login')->withoutMiddleware([FooMiddleware::class]);
If it's still does not help try putting your login route above the middlewared route.

Laravel Method [index#index] does not exist

I had Laravel 4.2 application and updating it to Laravel 5.4. for this i have installed fresh Laravel 5.4 and migrated routes,controllers views etc.
I want to protect all pages after /warehouse e.g /warehouse/dashboard,/warehouse/accounts and so on except /warehouse/login page. I have searched and used this route but its not working properly.
Can any one let me know whats the proper way of authentication.
Route::group(['middleware' => ['auth']], function() {
// uses 'auth' middleware
Route::resource('/warehouse','WarehouseController#index');
});
My login and verify routes are
Route::get('/warehouse/login', array('as' => 'WarehouseAdminLogin', 'uses' => 'WarehouseController#login'));
Route::post('/warehouse/verify', array('as' => 'WarehouseAdminVerify', 'uses' => 'WarehouseController#verify'));
For Route:resource there is no need to add function name after controller.
So try this:
Route::resource('/warehouse','WarehouseController');
And for Auth middlware you can do this :
Route::middleware(['auth']->group(function() {
// Auth routes
});
And it's obvious that login route should no be inside auth middleware!
How can a new guest user see login page?
Use Auth routes outside the auth middleware :
Route::get('login', 'Auth\LoginController#showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController#login');
Route::get('logout', 'Auth\LoginController#logout')->name('logout');

Laravel 5.2 Auth::login($user) not working

I am writing a Laravel 5.2 application. I need to manually login the user for which I am using \Auth::login($user). I am doing it in following way.
if ($user = User::where('phone',session('phone'))->first())
{
\Auth::login($user);
// \Auth::loginUsingId($user->id);
// Auth::attempt(['email' => $user->email, 'password' => 'password']);
$data = \Auth::user(); //returning correct results
}
I have tried all the options namely Auth::login($user), Authh:loginUsingId($user->id) and attempt method. These methods are working fine as the $data variable is storing the object of correct user. But the problem is when I move to other route say '/home' the user remain no more authenticated.
What might be the wrong here? How could I do it correctly?
Since Laravel 5.2, you have to attach all your routes that need session with the 'web' middleware. See your app/Http/Kernel.php, the 'web' middleware contains the \Illuminate\Session\Middleware\StartSession.
In routes you have to use web in laravel 5.2
Route::group(['middleware' => ['web', 'auth']], function () {
Route::get('/', 'HomeController#index');
Route::get('/profile', 'HomeController#profile');
});

Resources