I am working on a project with multiple authentication that has admins, students and teachers as three levels of authentication. I have changed default authenticable user model to student and added two more authenticable models that have their own logins.
I have the CourseController as follows:
use App\Course;
use App\Invoice;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class CourseController extends Controller
{
public function __construct()
{
$this->middleware('auth', ['only' => ['index']]);
$this->middleware('auth:teacher', ['only' => ['index']]);
$this->middleware('auth:admin', ['only' => ['index', 'create', 'store', 'edit', 'update', 'delete', 'search', 'destroy']]);
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$data = Course::get();
if (Auth::user()->role == 'admin') {
return view('admin.course.index', compact('data'));
} elseif (Auth::user()->role == 'student') {
return view('student.course.index', compact('data'));
} elseif (Auth::user()->role == 'teacher') {
return view('teacher.course.index', compact('data'));
}
}
}
config/auth.php as follows:(default guard is student)
'defaults' => [
'guard' => 'web',
'passwords' => 'students',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'students',
],
'api' => [
'driver' => 'token',
'provider' => 'students',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
],
'teacher' => [
'driver' => 'session',
'provider' => 'teachers',
],
'teacher-api' => [
'driver' => 'token',
'provider' => 'teachers',
],
],
My problem:
I want CourseController#index to be accessible for all three guards and pass the $data to their respective view. How would I modify the CourseController so that I can achieve this?? Please help
If you have any other ideas you can suggest me that too...
I think it's better to do it via route.
For student guard:
Route::group(['middleware' => ['auth']], function () {
Route::get('student.course.index', 'CourseController#index');
});
For teacher guard:
Route::group(['middleware' => ['auth:teacher']], function () {
Route::get('teacher.course.index', 'CourseController#index');
});
For admin guard:
Route::group(['middleware' => ['auth:admin']], function () {
Route::get('admin.course.index', 'CourseController#index');
//other routes
});
Thanks for the awesome submission! I ran into this problem myself a little while back and realized that doing things in just middleware was not the way to go.
I found that using Gates and Policies where the best route to take. So basically what this means is, each User has a Role, that Role has a Permission, and you are able to use the Blade #can directive to restrict access to certain parts of your site.
You can also use the middleware('can:accessCourse') method chaining in your web.php routes file (HTTP Routes Definition File) to make sure that the route is 'locked down' so to say. If you're using the Route::resource definition, then you can add the line $this->authorize('course.index'); to your index public function.
Using the constructor on your controller is great, but you should only use one middleware for that. I.E. $this->middleware('auth:admin'); Then once that person has 'admin' access, you can check to see if they have the Role and subsequent Permissions to do whatever it is you want.
Heres a short diagram I drew up showing what's going on in the background and to summarize all the stuff I just said.
https://drive.google.com/file/d/1uAcL7awPdxVai590WNuJFvDM_wIpsuYo/view?usp=sharing
Also BitFumes on Youtube has a tutorial series on how to create Admin Roles, Permissions, Defining Gates, Adding Policies, and using 'can' middleware on your Routes! Thats where I learned from myself! Now, he might be a little hard to understand as English isn't his first language, but he knows his stuff!
This link starts half way through a playlist about making a Blog, and starts with making administrator roles! :P
https://www.youtube.com/watch?v=aY7X5v37Ebk&index=25&list=PLe30vg_FG4OTELVqQgHaMaq2oELjpSWy_
Hope that this answer has helped you and guided you towards finding a solution to your problem!
Related
I have created two guards.Admin and Manager. To create authentication for admin I have followed https://blog.pusher.com/laravel-jwt/ this blog and it worked well. For my 2nd guard authentication middleware route manager not working. It says Manager not found.So I put only admin in group route and for manager I have declared the guard inside of auth method but It still not working. It can't find my model to store so I had to post the row data inside phpmyadmin manually and checked the login if it works or not but it's still not working. Returns the error part.
Api.php
Route::post('/manager/register', [App\Http\Controllers\ManagerUserController::class,'register']);
Route::post('/manager/login', [App\Http\Controllers\ManagerUserController::class,'authenticate']);
Route::get('open', [ManagerDataController::class,'open']);
Route::group(['middleware' => ['jwt.verify']], function() {
Route::get('user', [ManagerUserController::class,'getAuthenticatedUser']);
Route::get('closed', [ManagerDataController::class,'closed']);
});
Route::group(['middleware'=>'admin'],function($router){
Route::post('/admin/register', [App\Http\Controllers\AdminUserController::class,'register']);
Route::post('/admin/login', [App\Http\Controllers\AdminUserController::class,'authenticate']);
Route::get('open', [AdminDataController::class,'open']);
Route::group(['middleware' => ['jwt.verify']], function() {
Route::get('user', [AdminUserController::class,'getAuthenticatedUser']);
Route::get('closed', [AdminDataController::class,'closed']);
});
managerController:
public function authenticate(Request $request)
{
$credentials = $request->only('username', 'password');
if (! $token = auth()->guard('manager')->attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 400);
}
return response()->json(compact('token'));
}
auth.php
'defaults' => [
'guard' => 'admin',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'jwt',
'provider' => 'admins',
],
'manager' => [
'driver' => 'jwt',
'provider' => 'managers',
],
]
Another problem is if I set web for default guard then admin guard not working but if I put admin as default guard then it works. It this work like this then how can I use multi jwt authentication cause theres only single default guard exists!
i use this package :
https://github.com/spatie/laravel-permission/tree/v2
code :
$user=User::find(2);
$user->assignRole('admin');
and when i assign admin role to user I'm dealing with this error
There is no role named admin.Spatie\Permission\Exceptions\RoleDoesNotExist
this is my default guard in auth.php :
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
this is my roles table :
this is my role_has_permission table
and this is my permission table :
just add this protected property to your user model(or whatever model you are using for assigning permissions and roles).
protected $guard_name = 'api';
Add one of the following to your User model:
public $guard_name = 'api';
Or:
public function guardName()
{
return 'api';
}
As a convention it's best to do configurable things in the config file.
The problem with your code is the order of arranging your guards, just re-arrange as seen below.
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
...
Once this is done, you don’t need to add protected $guard_name = 'api'; to your User model, ensure to run php artisan config:clear
Ref: Saptie Laravel Permisions
friends! I found solution for this problem but first of all, i illustrate why this problem happened. As you know, Laravel read the codes from top to bottom and from left to right. Moreover when we want from laravel fresh all data by command
php artisan migrate :fresh --seed
It clears all this data and the problem begin. By other word, when assign Role command to check for new role it fails because all data is cleared before it access to those data. To avoid this we should set Role seeder class before Admin seeder class in database seeder
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
$this->call([RoleSeeder::class, AdminSeeder::class]);
}
}
Add this to your user model
use Spatie\Permission\Traits\HasRoles;
and in a user model class
use HasRoles;
Here is a reference
Complete example
This worked for me:
$role = Role::create(['guard_name' => 'admin', 'name' => 'manager']);
I have multiple guards for my site e.g.:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'recruiter' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'users',
],
],
Is there a method to check if a user is simply signed in i.e. authenticated regardless of any guards?
Currently I have to do something like this:
if (Auth::guard('web')->check() ||
Auth::guard('recruiter')->check() ||
Auth::guard('admin')->check()) {
}
I don't believe there is a single method for checking against all guards. Have you considered a middleware which encapsulates your auth guard checks so that at least then you don't have the checks peppered throughout your code base?
As others have stated this isn't a feature provided by Laravel. You will probably have to create something in user land code for this feature. I've created something that might work for your specific use case:
namespace Your\Namespace;
use Illuminate\Support\Facades\Auth;
class Guard
{
public static function checkAny(...$guards)
{
foreach($guards as $guard) {
if (Auth::guard($guard)->check()) {
return true;
}
}
return false;
}
}
if (\Your\Namespace\Guard::checkAny('web', 'admin','recruiter')) {
// don't show captcha
}
I am using multiple auth in my laravel project and it works fine:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admins' =>[
'driver' => 'session',
'provider' => 'admins',
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
But I have Problem with protecting some of my routes. I want these routes to be accessed by two type of authentication guards. if 'admins' guard user is logged in OR if 'users' guard user is logged in, I want to be able to access the route. now my route is like this:
Route::group(['middleware' =>'auth'], function () {
Route::get('/add/tutorial',[
'uses'=>'AddTutorialController#getAddTutorialIndex',
'as'=>'frontend.add.tutorial'
]);
});
and with this, just users from my 'users' guard can access this route.
I want to access maybe something like this:
Route::group(['middleware' =>['auth' OR 'auth:admins']],...
Is there any way to let both of auth guards access the route?? which kind of middleware group I should use?
If you could add an additional parameter to \app\Http\Middleware\Authenticate.php like:
public function handle($request, Closure $next, $guard = null, $default = false)
{
if($guard && $default) {
// check for specified $guard OR default guard
$authorized = Auth::guard($guard)->guest() || Auth::guard(null)->guest();
} else {
// use specified guard ( or null if non given )
$authorized = Auth::guard($guard)->guest();
}
if ($authorized) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
With that you can specifiy an additional parameter in a route group :
Route::group(['middleware' => 'auth:admins,true'], function() {
Route::get('/', function () {
dd('inside');
});
});
If you use auth:admins,true then the default guard and the specified guard (admins) would be checked with OR.
If you only use auth the default guard will be used. If you use auth:admins
the admins guard will be used only.
This is just a quick example. You can adjust it to your needs, or even write an own middleware.
i found 3 ways, if you can found useful:-
First Way:-
routes.php
Route::group(['middleware' =>['auth', 'auth:admins']], function () {
Route::get('/add/tutorial',[
'uses'=>'AddTutorialController#getAddTutorialIndex',
'as'=>'frontend.add.tutorial'
]);
});
Second Way:-
routes.php
Route::get('/add/tutorial',[
'uses'=>'AddTutorialController#getAddTutorialIndex',
'as'=>'frontend.add.tutorial'
])->middleware(['auth', 'auth:admins']);
Third Way:-
routes.php
Route::get('/add/tutorial',[
'uses'=>'AddTutorialController#getAddTutorialIndex',
'as'=>'frontend.add.tutorial'
])
yourcontroller.php
class YourController extends Controller{
public function __construct(){
$this->middleware(['auth', 'auth:admins']);
}
}
I am trying to authenticate users and admin form user table and admin table respectively. I am using the User model as provided by laravel out of the box and created the same for Admin. I have added a guard key and provider key into auth.php.
Guards
'guards' => [
'user' =>[
'driver' => 'session',
'provider' => 'user',
],
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
],
Providers
'providers' => [
'user' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
]
],
Routes
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');
});
I have created a directory called AuthAdmin where Laravel's default AuthController.php and PasswordController.php files are present. (Namespace Modified accordingly)
First of all, in Laravel's docs mentioned that how to specify custom guard while authenticating like this which isn't working.
There's another method mentioned in Laravel's docs to use a guard which is not working too.
It would be beneficial if someone could resolve the issues and correct me if I am wrong.
After lots of digging and lots of questions & answers I have finally managed to work Laravel 5.2 Multi Auth with two table, So I'm writing Answer of my own Question.
How to implement Multi Auth in Laravel 5.2
As Mentioned above.
Two table admin and users
Laravel 5.2 has a new artisan command.
php artisan make:auth
it will generate basic login/register route, view and controller for user table.
Make a admin table as users table for simplicity.
Controller For Admin
app/Http/Controllers/AdminAuth/AuthController
app/Http/Controllers/AdminAuth/PasswordController
(note: I just copied these files from app/Http/Controllers/Auth/AuthController here)
config/auth.php
//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' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
route.php
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');
});
AdminAuth/AuthController.php
Add two methods and specify $redirectTo and $guard
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');
}
it will help you to open another login form for admin
creating a 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.php
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\RedirectIfNotAdmin::class,
];
use this middleware in AdminController
e.g.,
middleware('admin');
}
public function index(){
return view('admin.dashboard');
}
}
That's all needed to make it working and also to get json of authenticated admin use
`Auth::guard('admin')->user()`
**Edit - 1**
We can access authenticated user directly using
`Auth::user()`
but if you have two authentication table then you have to use
Auth::guard('guard_name')->user()
for logout
Auth::guard('guard_name')->user()->logout()
for authenticated user json
Auth::guard('guard_name')->user()
##Edit 2
Now you can download Laravel 5.2 Multiauth implemented Project http://imrealashu.in/code/laravel/multi-auth-with-laravel-5-2-2/
In case this helps anyone, and this may just be due to my lack of understanding of middleware, here's what I had to do to get this working (in addition to the steps taken by #imrealashu)...
In route.php:
Route::get('/admin', [
'middleware' => 'admin',
'uses' => 'AdminController#index'
]);
This is in the web middleware group. Before this I tried putting it in a separate admin middleware group and even in an auth:admin group but this didn't work, it only worked for me when I specified the middleware as admin on the route itself. I have no idea why this is but I hope it saves others from pulling their hair out like I did.
It's very easy in laravel 5.6. Just go to config/auth.php and add this line in providers array:
'admins' => [
'driver' => 'database',
'table' => 'admin_table'
]
Note that we used database for driver not eloquent.
Now add this to guards array:
'admin_guard' => [
'driver' => 'session',
'provider' => 'admins'
]
Now we're done! Use this when working with admins table:
Auth::guard('admin_guard')->User();
Cheers.