I have implemented multi auth in app and everything is working fine except admin logout. I am trying to protect the admin.logout route using except() method but it is not working, executing the guest middleware and redirecting to the dashboard. Saw the route list and admin.logout route has still guest:admin middleware. I am trying to logout admin from adminLogout method controller function in AdminLoginController but it is not logging out admin. here are the pictures of my code. So how to resolve this admin logout issue?
auth.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
]
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
];
Web.php
//login routes for users
Route::get('/login', 'Auth\LoginController#showLoginForm')->name('login');
Route::post('/login', 'Auth\LoginController#login');
Route::post('/logout', 'Auth\LoginController#logout')->name('logout');
// routes for admin
Route::prefix('admin')->namespace('Admin')->group(function () {
Route::get('login', 'Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('login', 'Auth\AdminLoginController#adminLogin');
Route::post('logout', 'Auth\AdminLoginController#adminLogout')->name('adminlogout');
Route::post('hello', 'Auth\AdminLoginController#hello')->name('adminHello');
Route::group(['middleware' => ['role:admin']], function(){
Route::get('setting', 'AdminController#adminSetting');
Route::get('dashboard', 'AdminController#adminDashboard')->name('admin.dashboard');
Route::get('customers', 'AdminController#customers');
});
});
AdminLoginController.php
<?php
namespace App\Http\Controllers\Admin\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Spatie\Permission\Models\Role;
use App\Admin;
class AdminLoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest:admin')->except('adminlogout');
}
public function showLoginForm(){
return view('auth.admin.adminLogin');
}
public function adminLogin(Request $request)
{
$this->validate($request, [
'email' => 'required|email|exists:admins',
'password' => 'required|min:6'
]);
if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->get('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/admin/dashboard');
}
return back()->withInput($request->only('email', 'remember'));
}
public function adminLogout(Request $request)
{
Auth::guard('admin')->logout();
$request->session()->invalidate();
return redirect('/admin/login');
}
}
when I see all the routes list using php artisan route:list, it is showing me this
admin/logout route has still guest:admin middleware and it is not protecting my admin/logout route from guest:admin middleware and executing RedirectIfAuthenticated middleware even I put this route in except() method in AdminLoginController.
Kindly resolve how to logout from admin?
Related
I am trying to authorize users in Lumen from different tables using guards. What am I doing wrong? Please correct me.
I got False in login() (AuthController.php).
config/auth.php
'defaults' => [
'guard' => 'api',
'passwords' => 'members',
],
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'members',
],
'api-users' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
'providers' => [
'members' => [
'driver' => 'eloquent',
'model' => App\Members::class,
],
'users' => [
'driver' => 'eloquent',
'model' => App\Users::class,
],
],
AuthController.php
class AuthController extends Controller
{
public function __construct()
{
$this->middleware('jwt.auth', ['except' => ['login']]);
$this->middleware('jwt.auth:users', ['except' => ['login']]);
}
public function login()
{
$credentials = request(['email', 'password']);
$token = auth('users')->attempt($credentials); // Got here False
}
App/Users.php
class Users extends BaseModel implements Authenticatable, Authorizable
{
use Authorizable;
use Authenticatable;
protected $guard_name = 'users';
}
For my e-commerce app I use the default guard for user and made another one for the control panel admin but logging in or logging out a user affects the status in admin control panel as well and the opposite is true. Why is this?
Here is my auth file:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'user' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
Here is my admin login and logout controller:
public function enter(AdminLogin $admin){
$credentials = $admin->only(['email', 'password']);
if(Auth::guard('admin')->attempt($credentials)):
$admin = ModelsAdmin::whereEmail($admin->email)->first();
Auth::login($admin);
return redirect()->route('dashboard.show');
endif;
return redirect()->back()->withMsg("There is A worng in your Credentials");
}
public function logout(){
auth('admin')->logout();
return redirect()->route('admin.login');
}
And here is my user login and logout:
public function enter(UserCheck $user){
$credentials = $user->only(['email', 'password']);
if(Auth::guard('user')->attempt($credentials)):
$login = ModelsUser::whereEmail($user->email)->first();
Auth::login($login);
return redirect()->route('user.dashboard');
endif;
return back()->withMsg('Sorry sir you Entered invalid Credentials');
}
public function logout(Request $request){
Auth::guard('user')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('user.login');
}
the problem was in the admin middleware . i made check for admin by auth()->check() it should be auth('admin')->check() because there are another middleware for user is default so the two confilicted
So Basically we have two tables, one is the users table which is for the users of the site. The other is for people signing up for a webinar. We call this table Attendants. I want people to log into Attendant, and have Sanctum validate that, but I am running into issues. I get a 401 error.
I am using
Laravel 7
Vue 2
Axios
Env
SESSION_DRIVER=database
SESSION_DOMAIN=.server.local
SANCTUM_STATEFUL_DOMAINS=server.local,localhost,127.0.0.1
Cors
'paths' => [
'api/*',
'sanctum/csrf-cookie',
'webinars/newplatform/*'
],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
Guards and providers
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'web_attendant' => [
'driver' => 'session',
'provider' => 'attendants',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'sanctum' => [
'driver' => 'sanctum',
'provider' => 'users',
],
'sanctum_attendant' => [
'driver' => 'sanctum',
'provider' => 'attendants',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => Modules\User\Entities\User::class,
'table' => 'users'
],
'attendants' => [
'driver' => 'eloquent',
'model' => Modules\Webinar\Entities\Attendant::class,
],
],
Main.js
Vue.prototype.$axios = require('axios');
Vue.prototype.$axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
Vue.prototype.$axios.defaults.baseURL = frontPath;
Vue.prototype.$axios.defaults.withCredentials = true;
Login
this.$axios.get('/sanctum/csrf-cookie').then(response => {
this.$axios.post(`/webinar/${this.webinar}/login`, {
email: this.email,
password: this.password,
}).then(({data}) => {
//
})
});
So, When I try to login to the attendant, I get a successful Attendant model back, but any attempts made to the sanctum routes come back as 401.
Backend Login - Returns Attendant model
Auth::guard('web_attendant')->login($attendant);
return Auth::guard('web_attendant')->user();
Routes
Route::group(['middleware' => [ 'auth:sanctum_attendant' ] ], function()
{
Route::get('/webinar/{webinar}/attendant', [AuthController::class, 'attendant']);
Route::get('/webinar/{webinar}', [PlatformController::class, 'show']);
});
However, if i switch to login to the User Model instead of the Attendant model, the sanctum routes work
Auth::attempt(['email' => request()->email, 'password' => request()->password]);
return Auth::user();
Route::group(['middleware' => [ 'auth:sanctum' ] ], function()
{
Route::get('/webinar/{webinar}/attendant', [AuthController::class, 'attendant']);
Route::get('/webinar/{webinar}', [PlatformController::class, 'show']);
});
So I feel like I am missing something here. Any help would be appreciated
I found out the Sanctum guard defaults to the web guard, which uses the Users Table. So Sanctum was trying to authenticate the Attendant with the users table.
public function __invoke(Request $request)
{
if ($user = $this->auth->guard(config('sanctum.guard', 'web'))->user()) {
return $this->supportsTokens($user)
? $user->withAccessToken(new TransientToken)
: $user;
}
I got around this by adding
config(['sanctum.guard' => 'web_attendant']);
To my api.php file. Since My admin panel authenticates users and webinars authenticate attendants, I can't hard code in a guard in the sanctum.php config file
set a different table name in config/sanctum.php
Try this solution
this work for me
I'm testing with laravel sanctum but here some issues..
I'm creating Admin guard.
When I change the middleware to auth:sanctum_admin.. it should be only can access by admin but here I can access with normal user account with web guard. I don't know why?...I used passport with multiauth package.it's fine. but here in sanctum can't be separate User Table and Admin.
You can, also use multiple guards in sanctum. To achieve this, follow these steps -
Create your own guard as required. (In config/auth.php)
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
]
],
Set providers. (In config/auth.php)
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
Use this guard when you authenticate a user. (In route file)
if(auth()->guard('admin')->attempt($request->only('email','password')))
{
return auth()->guard('admin')->user();
}
#Abhishek Mitra
and for authorizatioin using Laravel Sanctum in case of Multiple Auth Guard, we can use middleware as such
Route::middleware(['auth:guard_name'])->get('/user', function(){
return auth()->guard('guard_name')->user();
}
config/auth.php
driver is sanctum
'guards' => [
'users' => [
'driver' => 'sanctum',
'provider' => 'users',
],
'partners' => [
'driver' => 'sanctum',
'provider' => 'partners',
],
'admins' => [
'driver' => 'sanctum',
'provider' => 'admins',
],
],
provider:
providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'partners' => [
'driver' => 'eloquent',
'model' => App\Models\Partner::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
model:
must be add Authenticatable
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Admin extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
Middleware:
Route::middleware(['auth:admin'])->get('/user', function(){
}
Guard:
auth()->guard('admin')->user();
Unauthenticated user message:
In app/Exceptions/Handler.php
use Illuminate\Auth\AuthenticationException;
function:
protected function unauthenticated($request, AuthenticationException $exception)
{
return response()->json(['message' => 'Unauthenticated.'], 401);
}
or
custom guard and custom redirect
public function render($request, Exception $exception)
{
$class = get_class($exception);
switch($class) {
case 'Illuminate\Auth\AuthenticationException':
$guard = array_get($exception->guards(), 0);
switch ($guard) {
case 'admin':
$login = 'admin.login';
break;
default:
$login = 'login';
break;
}
return redirect()->route($login);
}
return parent::render($request, $exception);
}
you must add your custom guard in config/auth.php.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'custom-guard' => [
'driver' => 'session',
'provider' => 'custom-provider',
]
],
be careful, the driver in custom guard must be session.
and set provider as:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'custom-provider' => [
'driver' => 'eloquent',
'model' => App\CustomProvider::class,
],
],
the App\CustomProvider::class must be the model.
after that can easily use the guard in auth.
auth('custom-guard')->user()
I also face the same issue and solved it by following -
In auth.php add an extra Guard - front
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'front' => [
'driver' => 'session',
'provider' => 'members',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => Vanguard\User::class,
],
'members' => [
'driver' => 'eloquent',
'model' => Vanguard\Member::class,
],
],
Log in as a Default User or Member
/** Default Guard**/
if (Auth::attempt(['username' => $credentials['username'], 'password' => $credentials['password']], $request->get('remember'))) {
}
/** Front Guard **/
if (Auth::guard('front')->attempt(['username' => $credentials['username'], 'password' => $credentials['password']], $request->get('remember'))) {
}
Finally add the Guard in sanctum.php
'guard' => ['front','web']
In config/auth.php:
'guards' => [
...
'api' => [
'driver' => 'sanctum',
'provider' => 'users',
],
],
(Tested in Laravel 9.x)
Defining API sanctum guards using the sanctum driver
'guards' => [
// Web Guards
'web' => [
'driver' => 'session',
'provider' => 'users',
],
//API Sanctum Guards
'admin-api' => [
'driver' => 'sanctum',
'provider' => 'admins',
],
'vendor-api' => [
'driver' => 'sanctum',
'provider' => 'vendors',
],
],
Defining Providers
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
'vendors' => [
'driver' => 'eloquent',
'model' => App\Models\Vendor::class,
],
],
Generating Token
$user = Admin::where('email', $request->email)->first();
$token = $user->createToken(uniqid());
return ['token' => $token->plainTextToken];
$user = Vendor::where('email', $request->email)->first();
$token = $user->createToken(uniqid());
return ['token' => $token->plainTextToken];
Protecting Routes using sanctum guard
Route::middleware('auth:admin-api')->get('/admin', function (Request $request) {
return $request->user();
});
Route::middleware('auth:vendor-api')->get('/vendor', function (Request $request) {
return $request->user();
});
I think the default guard should be like this:
'defaults'{
'guard' : "sanctum_admin",
'passwords': 'admins',
}
Or
'defaults'{
'guard' : 'web',
'passwords' : 'users',
}
In my Laravel instance, the guard or middleware is not working. My admin panel is always visible auth or non-auth. I don't understand what the problem is.
Route
Route::get('/admin', 'admin\adminController#index')->middleware('auth:admin');
Route::get('/admin-login', 'auth\adminLoginController#index');
Route::post('/admin-login', 'auth\adminLoginController#login')->name('admin.login.submit');
Controller
<?php
namespace App\Http\Controllers\auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Auth;
class adminLoginController extends Controller
{
function __construct()
{
$this->middleware('guest:admin');
}
public function index()
{
return view('auth.admin-login');
}
public function login(Request $request)
{
$this->Validate($request, [
'email' => 'required|email',
'password' => 'required|min:6'
]);
if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], false, false)) {
return redirect('/admin');
}
return redirect()->back()->with('message', 'Invalid Information');
}
}
If i delete __construct() , then i can visit admin log-in page , otherwise i cannot go in !!
my code of auth.php :
Guards :
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'admin-api' => [
'driver' => 'token',
'provider' => 'admins',
],
],
Providers
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\admin::class,
],
],
adminController
namespace App\Http\Controllers\admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
class adminController extends Controller
{
public function index()
{
$user = User::all();
$maleuser = User::where('gender', 'male')->get();
$femaleuser = User::where('gender', 'female')->get();
return view('admin/index')
->with('users', $user)
->with('maleusers', $maleuser)
->with('femaleusers', $femaleuser);
}
}
modify your Route to look like this
Route::get('/admin', 'admin\adminController#index')->middleware('auth:admin');
Route::get('/admin-login', 'auth\adminLoginController#index')->middleware('guest:admin');
Route::post('/admin-login', 'auth\adminLoginController#login')->name('admin.login.submit')->middleware('guest:admin');
also edit this line in your adminLoginController
function __construct()
{
$this->middleware('guest:admin')->except('logout');
}