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
Related
I'm a new Laravel Programmer and I tried to develop an web interface which uses the same login controller for two users which are from different tables. One user is Student and the other is Instructor. They are all routed to their intended page after login but I was wondering if there is any security issue to use this concept before I reach far? Or if there is any downside of using this logic or difficulties in implementing the logic or on trying securing the routes using middlewares?
Login Controller
public function store(LoginRequest $request)
{
$credentials = $request->only('username', 'password');
if(Auth::guard("instructor")->attempt($credentials))
{
return redirect()->route("instructor");
}
else if(Auth::guard("student")->attempt($credentials))
{
return redirect()->route("dashboard");
}
else
{
return back()->with('status', 'The provided credentials do not match our records.');
}
}
Middlewares
Route::middleware("auth:instructor")->group(function (){
Route::get("/instructorDashboard", [DashboardController::class, "instructor"])->name("instructor");
});
Route::middleware("auth:student")->group(function () {
Route::get("/dashboard", [DashboardController::class, "student"])->name("dashboard");
});
Dashboard Controller (They just return normal text, not view)
class DashboardController extends Controller
{
public function student (Request $request)
{
return "Your a Student";
}
public function instructor(Request $request)
{
return "Your a Instructor";
}
}
auth.php file
'defaults' => [
'guard' => 'student',
'passwords' => 'users',
],
'guards' => [
'student' => [
'driver' => 'session',
'provider' => 'students',
],
'instructor' => [
'driver' => 'session',
'provider' => 'instructors',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
'providers' => [
'students' => [
'driver' => 'eloquent',
'model' => App\Models\Student::class,
],
'instructors' => [
'driver' => 'eloquent',
'model' => App\Models\Instructor::class
],
'users' => [
'driver' => 'eloquent',
'model' => App\Models\Student::class,
]
]
Laravel authentication is really well thought and implemented system. It has been battle tested and proven to work in production environment. What you are doing does not causes any security vunurabilities. But it might constraint on some business logic and it's understandable if you have such requirements. So your answer to questions is
Is any security issue to use this concept?
No there is no issue from any security side. Keep in mind that security is not only in one place. You might have really secured authentication system but you need to make sure other parts if application are well implemented too.
Is there any downside of using this logic or difficulties in implementing the logic or on trying securing the routes using middlewares?
There is no issue with securing routes with middleware. There are some potential downsides but software is all about compromisation. There is no downside of implementing this logic as long as you have solid robust archietecture and documentation for code flow/implementation.
If you are trying to find out vunurabilities in system. They will usually be
in custom authorization of user than that of laravel has provided. If you are really afraid about security reach out to github and look for any security bugs also read about OWASP those are frequent bugs in applications.
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
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
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();
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