I'm using Laravel 5 on a Windows dev machine. I want to customize and use the Auth middleware throughout my application, to maintain authentication.
My use case is a standard one. There are two (or three) classes of users - Admin and Regular (regular would be all users that are not admin).
The Admin has the obvious role of backend management, and hence has a separate routing group /admin/, which should redirect an unlogged user to /admin/login. I have set it up like so..
Route::group(['middleware'=>'auth', 'prefix' => 'admin'], function() {
Route::get('login','App\AuthController#getLogin');
Route::post('login','App\AuthController#postLogin');
});
When the login form is posted, how do I ask Auth to add a filter
either that only validate from among those users where 'is_admin' is true?
or ask it to first join a User and a UserRoles table to identify only users with an Admin role?
I recommend you to define another middleware that detects if user is admin instead of modifying the auth. Now add this another middleware to your routes that only admins can access.
Add several middleware to route like this
Route::group(['middleware' => ['auth','admin']], function() {
Middleware will look something like
public function handle($request, Closure $next) {
if (Auth::user()->role == "admin") {
return $next($request);
} else {
return redirect("/")->withMyerror("You are not authorized for this action");
}
}
Why not instead of dealing with the Auth filter and trying to "validate" only on a certain condition, in your login code, just check what's the type of the user?
This is my high level code of doing it:
// get roles which are allowed to login to the admin panel
$roles = $this->userService->adminRoles();
$user = User::whereUsername(Input::get('username'))->whereIn('role_id', $roles)->first();
if (is_null($user)) {
// ...
}
// create our user data for the authentication
$userdata = array(
'username' => Input::get('username'),
'password' => Input::get('password'),
);
// attempt to do the login
// Auth::attempt($userdata) ....
This way you only do it once when you attempt the login and that's it?
Related
I currently can't pinpoint which solution is best in the following situation.
I need 2 different accounts namely: Customer and Admin.
However, both account types have different login Credentials i.e.
Admin logs in using email and password.
Customer logs in using username and customerCode.
I am currently using Laravel 8 with Jetstream.
I also created separate user models which both inherit Users Model, which is created automatically by JetStream
Is there a way where I can use different log in credentials for 2 different account types please? If so, what's the best way to go about this.
Thanks in advance.
Set up different auth guards, e.g. users and admin. This way, you can have separate login
https://laravel.com/docs/master/authentication#adding-custom-guards
You can specify which guard to use for relevant parts of your application. This could be done using route middleware, and you can set a default in config/auth.php
e.g.
use Illuminate\Support\Facades\Auth;
Auth::shouldUse('admin');
// or
Auth::guard('admin')->login(...);
// or
Auth::guard('users')->attempt($request->only('username', 'customer_code'));
Auth::guard('admin')->attempt($request->only('email', 'password'));
You can extend FortifyServiceProvider class and in boot method define your logic based on user role. This is a simple example.
public function boot()
{
// authenticate user using email or phone number
Fortify::authenticateUsing(function (Request $request)
{
$user = User::where('email', $request->username)
->orWhere('phone', $request->username)->first();
->orWhere('username', $request->username)->first();
if ($user &&
Hash::check($request->password, $user->password)
) {
return $user;
}
});
}
I'm really new to laravel and have been reading the documentations and tutorials. I'm planning on making an app that has 2 roles, admin and user. I modified my User model to have the column 'isAdmin' with boolean value since I only need 2 roles. How do I perform a check on this attribute during auth? Thank you.
TO answer your question, first of all to make protect any route using the auth middleware which ensures a user is authenticated (logged in) before they can access the route, you simply need to add the auth middleware.
e.g
web.php
<?php
Route::middleware('auth')->group(function(){
//All Routes which needs user to be logged in
});
or
//Individiual Route Middleware
Route::get('/path/to', 'controller#instance')->middleware('auth');
As for checking user role, you can basically create a middleware for this using the following steps:
run your php artisan make:middleware IsAdminMiddleware
open your IsAdminMiddleware and add this code inside the handle function:
public function handle($request, Closure $next)
{
if(!Auth::check()){
return redirect()->route('login');
}
if(Auth::user()->isAdmin == true){
return $next($request);
}
return redirect()->back()->with('unauthorised', 'You are
unauthorised to access this page');
}
it should forbid that the user grabs this url:
?main_title=banner
?main_title=law
?main_title=faq
with this
if(\Auth::user()->hasRole(['super_admin']))
I am going to assume that you are using spatie/laravel-permission based on your example code.
Laravel Permission comes with built-in role middlewares
One of the ways you could use them is by grouping the routes you want to be accessible only by super admins
Route::group(['middleware' => ['role:super_admin']], function () {
// YOUR ROUTES HERE
});
It's always good to using the middlewares ,
So in your case first create a Trait for roles
public function isSuperadmin(){
return Auth::user()->role->role=='superadmin';
}
After that create a middlewar like superadmin for the superuser and in that first include your trait
use App\Traits\Roles;
after that
use Roles;
public function handle($request, Closure $next)
{
if(!$this->isSuperadmin())
{
return back();
}
return $next($request);
}
and just register the middleware in the app/http/kernal.php in protected $routeMiddleware function
'superadmin' => \App\Http\Middleware\superadmin::class,
so it's make your life very easy now you don't need to check the url or role every time , for any url you want to block for other users just use
Route::get('/?main_title=law', 'HomeController#function')->middleware('superadmin')->name('admin-dashboard-home');
so if the user role is superadmin then he is allow to assess the url you can redirect the other users or show the error message :)
The delivered auth middleware that comes with Laravel 5 is great for user-only routes and controllers, however I want to add the ability to also check if the user is an administrator.
Currently, in my controllers, I have this for every class:
if (Auth::user()->level <= 1) {
// admin can do these actions
} else {
// redirect
}
It's very redundant and I'd like to look at what my options are. Since I want to retain the original auth middleware for user authentication, should I be building a new one for administrator authentication, or can I make some simple change in the original auth middleware that can account for my code above?
Middleware in Laravel 5.0 do not support arguments (this will be added in the upcoming 5.1 release).
Your options are to either create a separate middleware for this, or use route filters.
You can create a route filter by putting this in your RouteServiceProvider's boot method:
$router->filter('userLevel', function($route, $request, $level)
{
$user = auth()->user();
if ( ! $user || $user->level > $level)
{
return response('Unauthorized', 401);
}
});
Then use that filter in your routes:
Route::group(['before' => 'userLevel:1'], function($router)
{
// define routes...
});
With laravel we have a few auths setup for us which we can control in the routes file or setup in the controller constructor however I need to find a better way of doing this, and not sure if a route can handle it?
With my users, I allow themselves and the admin to edit them. So my controller looks like this.
function edit($id)
{
$user = User::findOrFail($id);
if(!Auth::user()->isAdmin() && $user->id != Auth::user()->id)
{
return Redirect::route('users.index')->withError('Unable to access that user');
}
return View::make('users.edit', compact('user'));
}
which is ok, but then on my update code I also have to do the same auth/user check to make sure a user or admin can only make changes to themselves.
So we get a double up, in some controllers this is repeated 3 times. Another example of context would be a forum post, the person who posted it or the admin can edit it.
Is there a way with route filters to handle doing this?
This may or may not be of use to you, I have a similar problem in my application where a user can only access their own user profile, but management can access anyone's.
My routes look like:
Route::get('user_profile/{user_id?}', array('as' => 'user_profile', 'uses' => 'UserController#get_user_profile'))->where(array('user_id' => '[0-9]+', 'tab' => '[A-Za-z]+'))->before('auth');
Route::when('user_profile/*', 'management');
This applies a management filter if the user attempts to go to a specific user, it defaults to their own profile if no ID is given.
Route::filter('management', function()
{
if(Helper::managementStatus() === NOT_MANAGEMENT)
return Redirect::route('home')
->with('flash_error', 'You must be logged in as a manager to view this page!');
});
Alternatively you could create a filter something like:
Route::filter('management', function()
{
$user = User::findOrFail(Input::get('user_id'));
if(!Auth::user()->isAdmin() && $user->id != Auth::user()->id)
{
return Redirect::route('users.index')->withError('Unable to access that user');
}
}
And then just apply that filter to the relevant routes.
I hope that's helpful.