Custom multi-auth guard logging & routing - php

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

Related

Laravel share session across domain

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

how to restrict the URL while login with admin panel in laravel

In my project the front end and back end in same laravel project, when admin is login in this case the if it has active session the admin user goes to front end of project i want to restrict the URL the admin user never go to front end while his session is active help me .
Route::get ('/shopping','FrontendController#index')->name('shopping.home');
This URL i want to restrict while active the admin user session.
other routes for front end
Route::group(['middleware'=>['frontlogin']], function() {
Route::get ('/shopping/product','FrontendController#product')->name('shopping.product');
Route::get ('/shopping/login','FrontendController#login')->name('shopping.login');
}
Middelware
public function handle($request, Closure $next)
{
if(empty(Session::has('frontSession'))) {
return redirect()->route('shopping.login');
}
return $next($request);
}
Where ever you are logging in the admin you will need to add your session key that your frontlogin middleware is checking for, frontSession:
Session::set('frontSession', true);
Or you will need to come up with a different mechanism to filter out who can not reach those routes protected by frontlogin.
check config/auth.php file.
you can define custom auth guards there. just define your guard names, drivers and providers there.
'guards' => [
'frontlogin' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
'table' => 'users'
],
],
You may check Laravel Authentication here

Get Middleware Name In Laravel Controller

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();

How to use token authentication in laravel web page

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

How to use different Auth for different controller in Laravel

I am creating a project in laravel. My problem is, Since this is a shopping cart I am using different tables for customer and admins. So if request is admin then i want to authenticate from admin table and if it is from store i want to use customer table for authentication. Is is it possible to set auth table for controllers or is it possible to use create multiple authenticator other than the default?
Multi Auth is a common problem that one can face in Laravel so yes it possible to create it.
You can write your own code for this or use some package for this specific functionality. They are available on github easily. Example link.
There is a very good tutorial for this here which I will use for explanation.
You will need to create two tables, customers and admin. The default user table can be used for customers (or other way too). The make:auth command will create all the routes, controllers and views for the users table auth.
For admin auth, first create an admin table. Next controllers
app/Http/Controllers/AdminAuth/AuthController
app/Http/Controllers/AdminAuth/PasswordController
Edit config/auth.php file and do same for admin as given for user, using admin model when required instead of user.
//Authenticating guards
'guards' => [
'user' =>[
'driver' => 'session',
'provider' => 'user',
],
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
],
//User Providers
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
]
],
//Resetting Password
'passwords' => [
'clients' => [
'provider' => 'client',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
'admins' => [
'provider' => 'admin',
'email' => 'admin.auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
Edit route file
Route::group(['middleware' => ['web']], function () {
//Login Routes...
Route::get('/admin/login','AdminAuth\AuthController#showLoginForm');
Route::post('/admin/login','AdminAuth\AuthController#login');
Route::get('/admin/logout','AdminAuth\AuthController#logout');
// Registration Routes...
Route::get('admin/register', 'AdminAuth\AuthController#showRegistrationForm');
Route::post('admin/register', 'AdminAuth\AuthController#register');
Route::get('/admin', 'AdminController#index');
});
Edit AdminAuth\AuthController.php file and add functions
protected $redirectTo = '/admin';
protected $guard = 'admin';
public function showLoginForm()
{
if (view()->exists('auth.authenticate')) {
return view('auth.authenticate');
}
return view('admin.auth.login');
}
public function showRegistrationForm()
{
return view('admin.auth.register');
}
Create middleware for admin
class RedirectIfNotAdmin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = 'admin')
{
if (!Auth::guard($guard)->check()) {
return redirect('/');
}
return $next($request);
}
}
Register middleware in kernel
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\RedirectIfNotAdmin::class,
];
Use this middleware in admin controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
class AdminController extends Controller
{
public function __construct(){
$this->middleware('admin');
}
public function index(){
return view('admin.dashboard');
}
}
Now you can use it like
Auth::guard('admin')->user()
but not directly like
Auth::user()
because we have two auths
You Should use ENTRUST (Laravel 5 Package)
But before you need to organize your database structure.
For all type of user use your users table, have a separate customer table with foreign key user_id. Assign roles to users , When a user logged in check its role and redirect to their dashboard as per assigned role.

Categories