I am facing a problem in my application.
Let there is two middleware
1)User
2)Admin
Is it possible to get which middleware I authenticated in my controller?
I am using Laravel 5.4.
Here is my route declaration
Route::group(['prefix' => 'user'], function () {
Route::group(['middleware' => ['auth:api']], function () {
Route::post('shop/store', 'ApiShopController#shopStore');
Route::post('shop/update', 'ApiShopController#shopUpdate');
});
});
Route::group(['prefix' => 'admin'], function () {
Route::group(['middleware' => ['auth:admin-api']], function () {
Route::post('shop/store', 'ApiShopController#shopStore');
Route::post('shop/update', 'ApiShopController#shopUpdate');
});
});
Here is my midlleware declaration
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
],
]
You should use Auth::guard('role')
You could include this in your Controller constructor to assign in the a middleware directly, for example like this:
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('home');
}
}
You could run this method in your controller aswell but I did not check it yet:
$middleware = $this->getMiddleware();
That should return the middleware in your controller
if your application has two guards 'admin' and 'user' in your config/auth.php
...
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
'user' => [
'driver' => 'session',
'provider' => 'user',
],
, then you can get current guard
#if(Auth::guard('admin')->check())
Hello {{Auth::guard('admin')->user()->name}}
#elseif(Auth::guard('user')->check())
Hello {{Auth::guard('user')->user()->name}}
#endif
My understanding about middleware is to help you do a filter on who you allow access a particular route/resources or intercept the request before it hits your resources in your Laravel app and that is why it is placed right during routes declaration or when the constructor is constructed; Check Middleware Introduction
However, for your case I would reconstruct my route declaration to look like this:
Route::group(['middleware' => ['auth:api']], function () {
Route::group(['prefix' => 'user'], function () {
Route::post('shop/store', 'ApiShopController#shopStore');
Route::post('shop/update', 'ApiShopController#shopUpdate');
});
Route::group(['middleware' => ['auth:admin-api']], function () {
Route::group(['prefix' => 'admin'], function () {
Route::post('shop/store', 'ApiShopController#shopStore');
Route::post('shop/update', 'ApiShopController#shopUpdate');
});
});
});
My observation though is that the call to user/shop/store for example will be hitting shopStore method in ApiShopController that admin/shop/store will it.
I advice that you either separate the methods for that each routes are meant to work on or you don't need middleware, since you'll be needing if conditions to be checking stuffs that your middleware would have done for you or you use different controllers for each middleware group.
PS: Let me know if there is something I missed about your question.
The config has what is currently the default guard. If you used the auth middleware than which ever guard did the authenticating is set as the current default:
config('auth.defaults.guard');
Auth::getDefaultDriver();
Related
I'm currently working on a laravel project that is hosted on a domain. A part of this application, some functionality, has to be on a different domain. I found a way, in my web.php, I mapped all routes with the :
Route::group(['domain' => config('app.main_domain')], function () {
and the routes that need to be on the other domain in the same manner, but with a different domain. Ok.
In the main domain, I create an image with the src attribute:
<img src="{{ config('second_domain') . DIRECTORY_SEPARATOR }}auth?id={{ \Illuminate\Support\Facades\Crypt::encrypt(\Illuminate\Support\Facades\Session::getId()) }}" style="display:none;"/>
pointing to this method route :
if ($request->has('id')) {
$session_id = Crypt::decrypt($request->get('id'));
Session::setId($session_id);
Session::start();
}
It's working. I share the same session over different domain, but, I would like to ask you guys if you know a better method for this case scenario. I know this is an old method that google used.
I have to say that the users need to remain authenticated in the different domain. I have looked at laravel passport, or laravel sanctum, but those are for API authenticating.
Any help will be apreciated.
For logging in different domains you should describe different "guards".
Configs
For example config/auth.php
'defaults' => [
'guard' => 'web', // or 'admin'
'passwords' => 'users',
],
'guards' => [
'admin' => [
'driver' => 'session',
'provider' => 'users',
],
'web' => [
'driver' => 'session',
'provider' => 'tourists',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
I use two guards in my project:
First one is 'admin', it's for admin panel and I use as provider User.php model.
Second one is 'web', it's for frontend or public site, use Tourist.php model, but you can use User model as well.
Controllers
You can use specific guard, In LoginController for admin panel:
protected function guard()
{
return Auth::guard('admin');
}
And for general domain of website
protected function guard()
{
return Auth::guard('web');
}
Routes
And finally you do ask me, How can I protect my routes, pfff, simply:
Route::group(['middleware' => 'auth:web'], function () {
Route::get('/', 'Cabinet\HomeController#index')->name('home');
});
Or for admin private routes
Route::group(['middleware' => 'auth:admin'], function () {
Route::get('/', 'Admin\HomeController#index')->name('home');
});
Read more about authentication https://laravel.com/docs/7.x/authentication#adding-custom-guards
I am trying to make auth through laravel package using admins table. In the project directory I added admin guard into config/auth.php
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
And in the guard array
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
Following is my login controller inside pacakge
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/admin/dashboard';
protected function redirectTo()
{
return '/admin/dashboard';
}
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function login(Request $request)
{
if(Auth::guard('admin')->attempt($request->only('email','password'), true)){
return redirect()
->intended(route('dashboard'))
->with('status','You are Logged in as Admin!');
}
}
}
and following is my dashboard controller
class DashboardController extends Controller
{
public function __construct()
{
/* dd(Auth::check()); */ //return false : just want to show you
$this->middleware('auth:admin');
}
public function index()
{
return view('xyz::dashboard');
}
}
And in my Admin.php Model following script is there
namespace App;
class Admin extends \ABC\xyz\App\Models\Admin
{
}
Which is extending package model
namespace ABC\xyz\App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
protected $table = 'admins';
}
And below are the routes from my package
$namespace = 'ABC\Xyz\App\Http\Controllers';
Route::group([
'namespace' => $namespace,
'middleware' => ['web'],
'prefix' => 'admin'
], function () {
Route::get('login', function(){
return view('xyz::auth.login');
})->name('login');
Route::post('/login', 'Auth\LoginController#login')->name('customLogin');
});
Route::group(['namespace' => $namespace,'prefix' => 'admin', 'middleware' => ['auth'] ], function () {
Route::get('dashboard', 'DashboardController#index')->name('dashboard');
});
When I try to login, after submitting valid details it does not redirecting me to dashboard, nothing happening. Also when I try for open forcefully /dashboard it take me to login page.
Also right after login attempt when I try Auth::check() it's returns true but same thing returning false in dashboardController.php construct function. In the same way Auth::guard('admin')->user() returns user's info while on dashboardController.php it's returns null.
Strange Result of php artisan route:list
As you can see in DashboardController.php construct I added $this->middleware('auth:admin');
So when I try to add dd(Auth::guard('admin')->user()) and then check in terminal php artisan route:list it returns null and sometime false, any idea why it is happening?
I don't know what and where I am missing something.
I would like to request you kindly guide me about it. I would appreciate.
Thank you
The problem is in your routes file:
Route::group(['namespace' => $namespace,'prefix' => 'admin', 'middleware' => ['auth'] ], function () {
Route::get('dashboard', 'DashboardController#index')->name('dashboard');
});
You are using the default guard with auth middleware. After you are logged in with admin guard you may not be logged in by your default web guard. That is why it fails and tries to redirect you to login page:
When I try to login, after submitting valid details it does not redirecting me to dashboard, nothing happening. Also when I try for open forcefully /dashboard it take me to login page.
Instead, you should specify in your group that you are using the admin guard:
Route::group(['namespace' => $namespace,'prefix' => 'admin', 'middleware' => ['auth:admin']], function () {
Route::get('dashboard', 'DashboardController#index')->name('dashboard');
});
However, you already specified in your DashboardController to use $this->middleware('auth:admin');, so there is no need to specifiy it in the route group again. The following is enough and reduces the likelihood to create an error:
Route::group(['namespace' => $namespace,'prefix' => 'admin'], function () {
Route::get('dashboard', 'DashboardController#index')->name('dashboard');
});
An extraction sample of the how you should define your admin model:
// app/Admin.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use Notifiable;
protected $guard = 'admin';
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
}
For more on multiple authentications guards see: How to use multiple authentication guards
Auth::guard('admin')->attempt($request->only('email','password') its returning true or false? If returning false then maybe toy didnt hashed your password
Try add this in your Model
public function setPasswordAttribute($password)
{
$this->attributes['password'] = Hash::make($password);
}
Please note that the Auth::check doesn't work on construct. this is because the middleware hasn't run yet, so Auth::check() should return false or null when you try to check in construct.
In your login controller, why are you using two redirectto?
protected $redirectTo = '/admin/dashboard';
protected function redirectTo()
{
return '/admin/dashboard';
}
it is better to stick with one :-)
inside your Admin.php , add this:
protected $guard = 'admin';
for your web.php routes, replace
Route::group(['namespace' => $namespace,'prefix' => 'admin', 'middleware' => ['auth'] ], function () {
Route::get('dashboard', 'DashboardController#index')->name('dashboard');
});
with
Route::group(['namespace' => $namespace,'prefix' => 'admin', 'middleware' => ['auth:admin'] ], function () {
Route::get('dashboard', 'DashboardController#index')->name('dashboard');
});
finally, in DashboardController.php
replace the
/* dd(Auth::check()); */ //return false : just want to show you
With:
$this->middleware(function ($request, $next) {
dd(Auth::check()); //return false : just want to show you
die;
});
Auth::check() should return true!
I'm developing a Laravel 6 app with 4 different users(with a different table for each). For this, I am using multi auth guard and created my first guard following this tutorial online (https://pusher.com/tutorials/multiple-authentication-guards-laravel).
Here is my custom guard "student"
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'student' => [
'driver' => 'session',
'provider' => 'students',
],
],
And Providers
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'students' => [
'driver' => 'eloquent',
'model' => App\Models\Student::class,
],
],
I have a custom login controller using a custom auth guard named 'student'
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Auth;
use Student;
class LoginController extends Controller
{
protected $redirectTo = '/dashboard';
public function __construct()
{
$this->middleware('guest')->except('destroy');
$this->middleware('student')->except('destroy');
}
public function studentLogin(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:5'
]);
if (Auth::guard('student')->attempt(['email' => $request->email, 'password' => $request->password], $request->get('remember'))) {
return redirect()->intended('admin/home')->with('smessage', 'Logged in successfully...!');
}
return back()->withInput($request->only('email', 'remember'));
}...
}
Now, Whenever I try to log in, It seems like I am logged in and redirected to the URL defined in the middleware/RedirectIfAuthenticated.php but this error pops up "Trying to get property of non-object" which is from the common header template where no data of logged user are available on auth()->user().
If I use 'middleware'=>'auth:student', I can access the route as student and have the logged user data via auth()->user(). same for admin using 'middleware'=>'auth' but passing both auth and auth:student as an array I can't get the logged user data via auth()->user() for both user.
Here are my routes:
Route::get('/', function () {
return view('welcome');
});
Route::get('/login', 'LoginController#create')->name('login');
Route::post('login', 'LoginController#store');
Route::get('/login/student', 'LoginController#create')->name('studentlogin');
Route::post('/login/student', 'LoginController#studentLogin');
Route::get('/logout', 'LoginController#destroy')->name('logout');
Route::group(['prefix'=>'admin', 'namespace' => 'Dashboard', 'middleware'=> 'auth' ], function () {
Route::get('home', 'DashboardController#display')->name('admin.home');
Route::get('users', 'UserlistController#display')->name('admin.userlist');
Route::post('users', 'UserlistController#store')->name('admin.create');
Route::delete('users/{id}', 'UserlistController#destroy')->name('admin.deleteuser');
});
Route::group(['prefix'=>'student', 'namespace' => 'Students', 'middleware'=> 'auth:student' ], function () {
Route::get('all', 'StudentsController#display')->name('student.all');
Route::delete('all/{id}', 'StudentsController#destroy')->name('student.delete');
Route::post('all', 'StudentsController#store')->name('student.store');
});
Couldn't find any solutions from other related topics on StackOverflow. Please do correct me if I have any mistakes somewhere or let me know if you want to inspect any other files for the code.
Thanks in advance.
You don't have any data on auth()->user() because you're querying the default guard which is web.
If you want to retrieve the logged user through student guard, you have to do auth()->guard('student')->user();
Also remember to pass everytime your guard to auth and middlewares that uses auth.
I.e.: if you need to make some routes restricted only to authenticated users you will need to do:
Route::group(['middleware' => 'auth:student'], function() {
// Your restricted routes
})
Omitting :student will use the default web guard as always
Note that if you need to restrict your routes to a group of users belonging to different guards you can pass those guards to auth:
Route::group(['middleware' => 'auth:web,student'], function() {
// Your restricted routes
}];
In this way Laravel will check for both web and student guards and will automatically set the one that belongs to the authenticated user. You will also be able to retrieve your user only by doing auth()->user() forgetting to pass the right guard
I defined two different guard in auth.php file like this :
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'website' => [
'driver' => 'session',
'provider' => 'websites',
]
]
There is two different section routes in web.php routes. one for website admn and another for normal users that is a member of those websites. like this :
Route::prefix('/website/{website}')->middleware('auth:website')->group(function () {
Route::group(['prefix' => 'banner_ads'], function () {
Route::get('banner_adsDatatable', ['as' => 'banner_adsDatatable', 'uses' => 'BannerAdsController#banner_adsDatatable']);
});
Route::resource('/banner_ads', 'BannerAdsController');
Route::prefix('/member/{member}')->middleware('auth:web')->group(function () {
Route::group(['prefix' => 'banner_ads'], function () {
Route::get('banner_adsDatatable', ['as' => 'banner_adsDatatable', 'uses' => 'BannerAdsController#banner_adsDatatable']);
});
Route::resource('/banner_ads', 'BannerAdsController');
});
});
Problem is that I have a resource controller (banner ads) that is shared with to users (website admins and members). As you can see I must to add it twice time.
But beacause for normal user I defined banner ads controller again, when I call banner_ads.update for example always return unAuthenticated user.
I do not know what can I do for solve this problem.
Seems like your auth:web middleware is inside auth:website. This is basically checking for an authenticated admin who is trying to access routes of an authenticated user.
You are trying to access routes as a normal user. So it is not working. Just replace your code with this:
Route::prefix('/website/{website}')->middleware('auth:website')->group(function () {
Route::group(['prefix' => 'banner_ads'], function () {
Route::get('banner_adsDatatable', ['as' => 'banner_adsDatatable', 'uses' => 'BannerAdsController#banner_adsDatatable']);
});
Route::resource('/banner_ads', 'BannerAdsController');
});
Route::prefix('/member/{member}')->middleware('auth:web')->group(function () {
Route::group(['prefix' => 'banner_ads'], function () {
Route::get('banner_adsDatatable', ['as' => 'banner_adsDatatable', 'uses' => 'BannerAdsController#banner_adsDatatable']);
});
Route::resource('/banner_ads', 'BannerAdsController');
});
I am trying to use JWT for laravel web page instead of session. so I made some changes.
Installed jwt-auth and configure
Then changed default guard as api in config/auth.php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
...
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
Now I am getting error
(1/1) FatalErrorException Call to undefined method
Illuminate\Auth\TokenGuard::attempt() in AuthenticatesUsers.php (line
75)
How to fix this and start token authentication for laravel web page(blades not API).
I'm also using jwt protecting our api. You should change your config like below:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
...
'api' => [
'driver' => 'jwt', // KEY POINT!!!
'provider' => 'users',
],
],
Make sure the jwt library installed correctly:
Tymon\JWTAuth\Providers\LaravelServiceProvider::class is added in your config/app.php.
Your user model implements JWTSubject interface if you use eloquent model in your provider.
I found the solution here : https://github.com/tymondesigns/jwt-auth/issues/860
In /routes/api.php - added a few basic authentication routes
Route::post('login', 'Auth\LoginController#login');
Route::get('/user', function (Request $request) {
$user = $request->user();
return dd($user);
})->middleware('auth:api');
In /app/http/Controller/auth/LoginController.php
and then override methods in login contoller
public function login(Request $request)
{
$credentials = $request->only(["email","password"]);
if ($token = $this->guard()->attempt($credentials)) {
return $this->sendLoginResponse($request, $token);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
protected function sendLoginResponse(Request $request, $token)
{
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user(), $token);
}
protected function authenticated(Request $request, $user, $token)
{
setcookie("jwt_token", $token);
return redirect('/');
return response()->json([
'token' => $token,
]);
}
protected function sendFailedLoginResponse(Request $request)
{
return response()->json([
'message' => "not found",
], 401);
}
Adding middleware AddToken
public function handle($request, Closure $next)
{
$token = isset($_COOKIE["jwt_token"])?$_COOKIE["jwt_token"]:"";
//$request['token'] = $token;//this is working
$request->headers->set("Authorization", "Bearer $token");//this is working
$response = $next($request);
//$response->header('header name', 'header value');
return $response;
}
Register middleware in Kernel.php
protected $middleware = [
....
\App\Http\Middleware\AddToken::class,
];
I think you can try this :
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
EDIT
You can find some help from the step by step example. In this example you need to focus on how to configure and use that token base authentication.
Hope this help you well.
Please refer this link. If you are using api as default then laravel authentication will throw an error.
Laravel uses default Session based authentication out of the box with the default scaffolding users-view-controller that you already have. You have additional means of adding your own custom guard in the doc, so you can make use of the guard as needed.
Therefore as #KevinPatel suggested, revert back to the default configuration, then in your route: group the route you want to be under JWT authentication, add the JWTMiddleware, in this case you have to update the controller responsible for your authentication to use the JWTAuth instead of the default auth.
You should check this answer if you need to understand it better check this answer on Laracasts
One recommended way to incorporate the JWTAuth is to go for Dingo API (of course you are not building api, but) because Dingo already added some flesh to the authentication and other routes management - so things are pretty easy to use and configure