I use Laravel 5.2 and have a problem with middleware.
There is the code in the routes.php
use Illuminate\Contracts\Auth\Access\Gate;
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/', 'HomeController#index');
});
Route::group(['prefix'=>'admin', 'middleware' => 'admin'], function(){
Route::get('/', function(){
return view('admin.index');
});
Route::get('/user', function(){
return view('admin.user');
});
});
Kernel.php:
protected $routeMiddleware = [
...
'admin' => \App\Http\Middleware\AdminPanel::class,
];
AdminPanel.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\Role;
class AdminPanel
{
public function handle($request, Closure $next)
{
$user = Auth::user();
dd($user);
if($user){
$role = Role::whereName('admin')->first();
if($user->hasRole($role)){
return $next($request);
}
}
return redirect('/');
}
So, $user = Auth::user() always return null.
Thanks for suggestions!
I faced a situation where Auth::user() always returns null, it was because I was trying to get the User in a controller's constructor.
I realized that you can't access the authenticated user in your controller's constructor because the middleware has not run yet.
As an alternative, you can define a Closure based middleware directly in your controller's constructor.
namespace App\Http\Controllers;
use App\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
class ProjectController extends Controller
{
protected $user;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->user = Auth::user();
return $next($request);
});
}
}
Any route that uses Auth() must be encapsulated in the web middleware. You're close, just move your Route::group(['prefix' => 'admin'], ...) into the group above.
Route::group(['middleware' => 'web'], function () {
Route::auth();
Route::get('/', 'HomeController#index');
// Moving here will ensure that sessions, csrf, etc. is included in all these routes
Route::group(['prefix'=>'admin', 'middleware' => 'admin'], function(){
Route::get('/', function(){
return view('admin.index');
});
Route::get('/user', function(){
return view('admin.user');
});
});
});
Define middleware in the constructer of your controller and it will do the trick here
public function __construct()
{
$this->middleware('auth:api');
}
I had the same problem because i did not set the table name.
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'users';
I found a solution in an old code
function getAuth($guard, $get)
{
return auth($guard)->user()->$get;
}
add this ^ as a helper function and use it wherever you want
ex:
getAuth('user', 'id');
just include your authentication middleware in call
$user = auth('middleware')->user()
Route::middleware('auth:api')->group(function () {
Route::get('/details', 'UserController#details');
});
My Auth::user() return null in view when
I don't have users table in database
I don't have id field as primary key of table users
Related
I'm going to assign all routes to Admin role, a few routes to operation role and a few routes to other roles in my App. I've tried to use group middleware in Laravel 8.
The code for Admin Role alone works fine. But, when I add middleware to other roles in the route group, it's not functioned how I expected.
My code:
Web.php:
Route::middleware(['role:Admin'])->group(function () {
Route::get('/', function () {
return redirect('/home');
});
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/employee_register', [App\Http\Controllers\EmployeeRegisterController::class, 'index'])->name('employee_register');
Route::post('/employee_register', [App\Http\Controllers\EmployeeRegisterController::class, 'save'])->name('employee_save');
Route::post('/DoAsync', [App\Http\Controllers\AjaxController::class,'ajaxTask'])->middleware('only.ajax');
Route::get('/job_booking', [App\Http\Controllers\JobBookingController::class, 'index'])->name('job_booking');
Route::post('/DoAsync_jb', [App\Http\Controllers\JobBookingAjaxController::class,'ajaxTask'])->middleware('only.ajax');
Route::post('/DoAsync_ai', [App\Http\Controllers\AssignInchargeAjaxController::class,'ajaxTask'])->middleware('only.ajax');
});
Route::middleware(['role:operation'])->group(function () {
Route::get('/', function () {
return redirect('/job_booking');
});
Route::get('/home', function(){
return redirect('/job_booking');
})->name('home');
Route::get('/job_booking', [App\Http\Controllers\JobBookingController::class, 'index'])->name('job_booking');
Route::post('/DoAsync_jb', [App\Http\Controllers\JobBookingAjaxController::class,'ajaxTask'])->middleware('only.ajax');
Route::post('/DoAsync_ai', [App\Http\Controllers\AssignInchargeAjaxController::class,'ajaxTask'])->middleware('only.ajax');
});
The Middleware
(EnsureUserHasRole):
class EnsureUserHasRole
{
public function handle(Request $request, Closure $next, string $role)
{
//I received Call to a member function roles() on null error when accessing login and logout.
// So, I used this to avoid role check on login & logout routes.
if ( $request->route()->named('login') || $request->route()->named('logout') ) {
return $next($request);
}
elseif ($request->user()->roles()->where('role', '=', $role)->exists()) {
return $next($request);
}
abort(403);
}
}
Models:
User:
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $fillable = [
'employee_id',
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function roles()
{
return $this->belongsToMany(Role::class, 'role_user');
}
}
Role:
class Role extends Model
{
use HasFactory;
public function users()
{
return $this->belongsToMany(User::class, 'role_user');
}
}
Without the second Middleware (middleware(['role:operation'])), all routes would be accessed. But, then adding it, the if condition in EnsureUserHasRole middleware executes the abort(403)
Should I use any if in the middleware in web.php?
Note: middleware('only.ajax') has been used to ensure the controller is accessed only on Ajax call
You are duplicating the routes. If you run php artisan route:list you will notice that half of your routes are missing.
Lets take an example route '/', what you did is similar to this:
Route::get('/', function () {
return redirect('/home');
})->middleware(['role:Admin']);
Route::get('/', function () {
return redirect('/job_booking');
})->middleware(['role:operation']);
As you can see routes duplicates.
To avoid this you need to add prefix to your routes like:
Route::get('/admin', function () {
return redirect('/home');
})->middleware(['role:Admin']);
Route::get('/operation', function () {
return redirect('/job_booking');
})->middleware(['role:operation']);
Check out Laravel Routing for more information.
What I'm trying to do is group multiple prefixes with one middleware:
Route::group(['middleware' => ['centralize']], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setLocale()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setCountry()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setCity()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setArea()], function () {
//routes
});
});
});
});
});
I have added the centralize middleware to kernel:
protected $routeMiddleware = [
...
'centralize'=> \App\Http\Middleware\Centralize::class,
...
];
But the middleware is not being called at all, is there is something missing here?
EDIT: it goes directly to the view of the home, I am doing dd inside of the middleware but it never reaches there!
EDIT: middleware code:
<?php
namespace App\Http\Middleware;
use App\Utilities\Centralization;
use Closure;
use Illuminate\Http\RedirectResponse;
class Centralize
{
/**
* #var \Illuminate\Http\Request
*/
private $request;
/**
* #var array
*/
private $params;
private $location;
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(\Illuminate\Http\Request $request, Closure $next)
{
$this->request = $request;
dd('hit');
$this->params = explode('/', $request->getPathInfo());
$this->figureLocale();
$this->figureCountry();
$this->figureCity();
$this->figureArea();
$this->figureLocation();
$redirection = implode('/', $this->params);
if ($request->getPathInfo() !== $redirection) {
return new RedirectResponse($redirection, 302, ['Vary' => 'Accept-Language']);
}
\View::share([
'countries' => Centralization::getCountries(),
'cities' => Centralization::getCities(),
'areas' => Centralization::getAreas(),
'location' => $this->location
]);
return $next($request);
}
private function figureLocale()
{
//...
}
private function figureCountry()
{
//..
}
private function figureCity()
{
//...
}
private function figureArea()
{
//...
}
private function figureLocation()
{
//...
}
}
EDIT: I also have tried:
Route::middleware(['centralize'])->group(function () {
Route::group(['prefix' => \App\Utilities\Centralization::setLocale()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setCountry()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setCity()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setArea()], function () {
//..
});
});
});
});
});
But with the same result , it never hits the middleware!
EDIT: clearing cache using artisan and manual doesn't work either!
Group route middleware called like this:
In routes/web.php
Route::group(['middleware' => ['centralize']], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setLocale()], function () {
Route::group(['prefix' => \App\Utilities\Centralization::setCountry()], function () {
//routes
});
});
});
In app/Http/kernal.php
protected $routeMiddleware = [
'centralize' => \App\Http\Middleware\CentralizeMiddleware::class,
];
In app/Http/Middleware/CentralizeMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class CentralizeMiddleware
{
public function handle($request, Closure $next)
{
if (//Your Condition) {
//If true
}
else {
return $next($request);
}
}
}
You mentioned in one edit that:
it goes directly to the view of the home
So the URL you are visiting is actually /. And as clarified in the comments, the "home" route was defined nested inside the prefixes. But that means it is really a route for something like /fr/france/paris/somewhere/, and not a route for /.
The prefix in the route means "this route applies to URIs with this prefix". If a URI does not include that prefix, this routing is not applied.
So that means there is no route for /, and visiting it will:
not fire the centralize middleware;
not find a matching route, so throw a 404;
If you want to apply your centralize middleware to your home route, you'll need to place it inside that group, but outside the prefixes:
Route::middleware(['centralize'])->group(function () {
Route::get('/', 'HomeController#index')->name('home');
Route::group(['prefix' => \App\Utilities\Centralization::setLocale()], function () {
// ...
});
});
i found a issue it say 'Class admin does not exist'. Anything I missing for the issue? Thanks.
Here is my Route.php
Route::group(['prefix' => 'admin', 'middleware'=> ['auth' => 'admin']], function () {
Route::get('/','AdminController#index');
Route::get('profile','AdminController#profile');
Route::get('/addProduct','AdminController#addProduct');
});
Here is my AdminController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdminController extends Controller
{
public function index(){
return view('admin.index');
}
public function profile(){
return view('admin.profile');
}
public function addProduct(){
return view('admin.addProduct');
}
}
Issue with in the route file to assign middlewares to route group
If you have two middlewares then assign like this ["auth", "admin"] instead of ["auth" => "admin"].
Route::group(['prefix' => 'admin', 'middleware'=> ['auth', 'admin']], function () {
Route::get('/','AdminController#index');
Route::get('profile','AdminController#profile');
Route::get('/addProduct','AdminController#addProduct');
});
If i go to http://www.yourdomain.com/admin/login i see my login page.
If i go to http://www.yourdomain.com/admin/example i have the redirect to http://www.yourdomain.com/login without the admin.
My web routes:
Auth::routes();
Route::prefix('admin')->group(function() {
Route::get('/login','Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login','Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/manifiesto','AdminController#getIndex')->name('admin.dashboard');
Route::get('/logout','Auth\AdminLoginController#logout')->name('admin.logout');
Route::get('/trabajadores','AdminController#showTrabajadores')->name('admin.trabajadores');
Route::get('/clientes','AdminController#showClientes')->name('admin.clientes');
Route::get('/proyectos','AdminController#showProyectos')->name('admin.proyectos');
Route::get('/administradores','AdminController#showAdmins')->name('admin.administradores');
});
When i put some url with the /admin before and user isn't logged, i want to redirect to /admin/login.
Thanks.
More info:
App/http/Controllers/Auth/AdminLoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Auth;
class AdminLoginController extends Controller
{
protected $loginPath = 'admin/login';
public function __construct()
{
$this->middleware('guest:admin', ['except' => ['logout']]);
}
public function showLoginForm()
{
return view('backend.public.pages.login');
}
public function login(Request $request)
{
//validate the form data
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:6'
]);
//attempt to log the user in
if (Auth::guard('admin')->attempt(['email' => $request->email, 'password' => $request->password], $request->remember)){
//if successful, then redirect to their intended location
return redirect()->intended(route('admin.dashboard'));
}
return redirect()->back()->withInput($request->only('email','remember'));
}
public function logout()
{
Auth::guard('admin')->logout();
return redirect('/');
}
}
App\Http\Middleware\AdminAuthenticate.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminAuthenticate
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('admin/login'); // <--- here
}
}
return $next($request);
}
}
Create an middleware
php artisan make:middleware AuthAdmin
Check for guest in the handle method of the middleware
public function handle($request, Closure $next)
{
if (Auth::guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('admin/login');
}
}
return $next($request);
}
Add a key to the middleware in app/Http/Kernel.php in $routeMiddleware array
'auth_admin' => \App\Http\Middleware\AuthAdmin::class
Attach the auth_admin middleware to the group
Route::group(['prefix' => 'admin', 'middleware' => 'auth_admin'], function() {
// Your admin routes except login
});
write bellow code in your route.php file
Route::group(array('prefix' => 'admin'), function() {
Route::controller('login', 'AdminloginController');
});
Route::group(array('before' => 'admin_ajax', 'prefix' => 'admin'), function()
{
//route for pages which are render after login
});
Route::get('/admin', function() {
return View::make('admin.loginform');
});
And Write bellow code in your filter.php file
Route::filter('admin_ajax', function() {
if (!Auth::admin()->check()) {
return Redirect::to('admin/login');
} else {
}
});
And if you are using laravel 5.4
Route::get('/manage', function () {
return redirect('manage/login');
});
Route::group(['prefix' => 'manage'], function() {
//login bypass for the below listed controllers
Route::resource('login', 'AdminLoginController#showLoginForm');
Route::post('dologin', 'AdminLoginController#login');
});
All you can do is add the auth middleware like this :
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function() {
Route::get('/login','Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login','Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/manifiesto','AdminController#getIndex')->name('admin.dashboard');
Route::get('/logout','Auth\AdminLoginController#logout')->name('admin.logout');
Route::get('/trabajadores','AdminController#showTrabajadores')->name('admin.trabajadores');
Route::get('/clientes','AdminController#showClientes')->name('admin.clientes');
Route::get('/proyectos','AdminController#showProyectos')->name('admin.proyectos');
Route::get('/administradores','AdminController#showAdmins')->name('admin.administradores');
});
But by default this will redirect to /login, if you want to override this you have two chocies depending on if you have other type of users that uses the /login route or not !!
If NO ONE uses /login route
1- You need to modify App\Http\Middleware\Authenticate::handle() method and change /login to admin/login.
2- Then you need to add $loginPath property to your \App\Http\Controllers\Auth\AuthController class.
Authenticate
namespace App\Http\Middleware;
class Authenticate {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('admin/login'); // <--- here
}
}
return $next($request);
}
}
AuthController
namespace App\Http\Controllers\Auth;
class AuthController extends Controller
{
protected $loginPath = 'admin/login'; // <--- here
// ... other properties, constructor, traits, etc
}
If there is someone using /login route
You must create you own middleware and do what it takes for auth checking in the handle method with redirecting to your admin/liging route :)
In this case :
Add the following line in $routeMiddleware property at app/Http/Kernel.php file
'adminAuth' => \App\Http\Middleware\YourNewMiddleware::class,
Don't forget to add your new middleware in route group as follow
Route::group(['prefix' => 'admin', 'middleware' => 'adminAuth'], function()
{
// your admin routes
});
Make an another middleware for admin. follow the step
Make a file named AdminAuthenticate in app/Http/Middleware location and copy the content of Authenticate in New file
change the Class name as AdminAuthenticate
Change the content of handle function as show below
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/admin/login');
}
}
return $next($request);
}
Add the following line in $routeMiddleware array at app/Http/Kernel.php file
'AdminAuth' => \App\Http\Middleware\AdminAuthenticate::class,
Now everything is okay. just add your new middleware in route group as follow
Route::group(['prefix' => 'admin', 'middleware' => 'AdminAuth'], function()
{
// all admin routes
});
Or you can add new middleware to constructor function of every admin controller as like below
$this->middleware('AdminAuth');
I have a problem that I can not resolve in Laravel 5.4.
I'm using the Postman extension to make requests for my API, so far it works normally with GET, but when I try to do a POST, the method that's actually called is GET again. (The API can not have authentication or token for the user).
api.php:
<?php
use Illuminate\Http\Request;
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::group(['api' => ['auth:api']], function(){
Route::group(['prefix' => 'user'], function(){
Route::get('{id}', ['uses' => 'UserController#getUser']);
Route::post('', ['uses' => 'UserController#saveUser']);
Route::get('', ['uses' => 'UserController#allUsers']);
Route::put('{id}',['uses' => 'UserController#updateUser']);
Route::delete('{id}', ['uses' => 'UserController#deleteUser']);
});
});
UserController.php:
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
class UserController extends Controller{
protected $user = null;
public function __construct(User $user){
$this->user = $user;
}
public function allUsers(){
return $this->user->allUsers();
}
public function getUser($id){
}
public function saveUser(){
return $this->user->saveUser();
}
public function updateUser($id){
}
public function deleteUser($id){
}
}
User.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public $hidden = ['venda','remember_token', 'created_at','updated_at'];
public $fillable = ['nome','email', 'venda'];
public function allUsers(){
return self::all();
}
public function saveUser(){
$input = Input::all();
echo 'aa';
$user = new User();
$user->fill($input);
$user->save();
return $user;
}
}
First change this:
Route::group(['api' => ['auth:api']], function(){
To:
Route::group(['middleware' => ['auth:api']], function(){