I need to redirect an admin user to the dashboard after he logs in. To achieve this, I've overriden the redirectPath() method that is located in RedirectUsers trait. Here is the code:
public function redirectPath()
{
if (property_exists($this, 'redirectPath')) {
return $this->redirectPath;
}
// MODIFICATIONS ------------------------------
if(request()->user()->hasRole('admin')){
return '/dashboard';
}
// ENDMODIFICATIONS ---------------------------
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}
The problem
Dashboard redirection works only in some cases:
At first login, the admin is redirected to the home page.
At subsequent logins, the admin is redirected to the dashboard.
But if php artisan cache:clear command is run, admin gets redirected to the home page again.
Why is this happening and how do I implement this functionality correctly?
Instead of overriding redirectPath(), you can create authenticated method in your AuthController.php, it will be called if exists after user successfully authenticated:
class AuthController extends Controller
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
...
public function authenticated()
{
if(Auth::guard($this->getGuard())->user()->hasRole('admin')){
return redirect('/dashboard');
}
return redirect()->intended($this->redirectPath());
}
}
How about middleware.
Make a middleware named RedirectIfAdmin.
Then place it in to the Homecontroller __construct.
I think this maybe more like laravel thinking.
NEVER CHANGE ANYTHING ANY FILES IN VENDOR FOLDER!
It will cause issues when you are trying to update the packages as it will overwrite everything that is old! Also, by default, git will not track any files inside vendor folder
Here is the alternative and how it supposed to work:
Add $redirectTo attribute in your AuthController.php
class AuthController extends Controller {
protected $redirectTo = '/user/dashboard';
}
Then, in your controller, you can do something like this:
if(Auth::guard($this->getGuard())->user()->hasRole('admin')){
$this->redirectTo = '/dashboard'
}
What will happen:
public function redirectPath()
{
if (property_exists($this, 'redirectPath')) {
return $this->redirectPath;
}
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}
Whenever any method calling redirectPath function, it will check if the attribute of redirectPath is exist or not. If exist, use the provided url instead. If not, use the default which is '/home`
Related
I need some help with redirects after login with Laravel 8 Fortify. I know how to do it in a login controller but with Fortify there is a LoginResponse that I am not sure how to do this. I know in RouteService Provider I can change it to whereever but I have roles that I want to redirect to different dashboards based on role.
In the old Login Controller I would do the following. How would I change this to the LoginResponse for Fortiy?
public function redirectTo()
{
if(Auth::user()->hasRole('admin')){
$this->redirectTo = route('admin.dashboard');
return $this->redirectTo;
}
if(Auth::user()->hasRole('manager')){
$this->redirectTo = route('manager.dashboard');
return $this->redirectTo;
}
if(Auth::user()->hasRole('employee')){
$this->redirectTo = route('employee.dashboard');
return $this->redirectTo;
}
}
You can Customize Redirects with Fortify by binding your own implementation of the LoginResponse. You could add the following to the register method of your FortifyServiceProvider:
use Laravel\Fortify\Contracts\LoginResponse;
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->instance(LoginResponse::class, new class implements LoginResponse {
public function toResponse($request)
{
if($request->user()->hasRole('admin')){
return redirect()->route('admin.dashboard');
}
if($request->user()->hasRole('manager')){
return redirect()->route('manager.dashboard');
}
if($request->user()->hasRole('employee')){
return redirect()->route('employee.dashboard');
}
}
});
}
If you'd prefer you can always create the class in an actual file instead of using an anonymous class.
Here is a Laravel News post that goes into it in a little more details.
Since you seem to have a custom dashboard for each role, if it were me instead of changing the under the hood as Rwd suggested I would make my default redirect page which is in /config/fortify.php as the home directory to be the page that handles the redirect. So your route('dashbord') will decide which dashboard the user needs:
Route::middleware([...])->group(function () {
Route::get('/dashboard', function () {
if(Auth::user()->hasRole('admin')){
$redirectTo = route('admin.dashboard');
}
if(Auth::user()->hasRole('manager')){
$redirectTo = route('manager.dashboard');
}
if(Auth::user()->hasRole('employee')){
$redirectTo = route('employee.dashboard');
}
return redirect()->to($redirectTo);
})->name('dashboard');
});
What happens to me is that if the user puts the url: project.test/med, the system redirects to Login but then it does not redirect to dashboard but to med. In RedirectIfAuthenticated the expression Auth::guard($guard)->check() is not evaluated or at least in the Log it is not shown, so I am not able to identify what is happening.
/** RedirectIfAuthenticated.php */
public function handle($request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
Log::info($request);
Log::info(Auth::user());
foreach ($guards as $guard) {
Log::info(Auth::guard($guard)->check());
Log::info(Auth::check());
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
Log::info(Auth::check());
Log::info('end');
return $next($request);
}
/** web.php */
Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
return Inertia\Inertia::render('Dashboard');
})->name('dashboard');
Route::middleware(['auth:sanctum','verified'])->get('/med', function (Request $request) {
return Inertia\Inertia::render('Med');
})->name('med');
Go to config/fortify.php and modify this line:
'home' => RouteServiceProvider::HOME,
to:
'home' => function(){
//if you want to go to a specific route
return route('dashboard');
//or if you have a bunch of redirection options
if (Auth::user()->hasRole('admin')) {
return route('admin.dashboard');
}
else{
return route('guest.dashboard');
}
}
EDIT: Fortify now ships with a simpler way of doing this. See this answer for simplified way.
The RedirectIfAuthenticated middleware does not do what you think it does. This middleware checks to see if a user is authenticated when trying to access a route with the guest middleware attached to it. So after you login to the application and you try to access /login route, this middleware will intercept the request and redirect the user to the RouteServiceProvider::HOME path.
With that being said, at the time of this writing, Laravel Fortify does not offer the ability to easily modify where the user gets redirected after registering or logging in to the application. See issue for more info
To get this to work you will have to go through a few steps.
Step 1 - Create new LoginResponse class
Anywhere in your application create a LoginResponse class and implement Laravel\Fortify\Contracts\LoginResponse.
<?php
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
/**
* #inheritDoc
*/
public function toResponse($request)
{
return $request->wantsJson()
? response()->json(['two_factor' => false])
: redirect()->intended(config('fortify.home')); // This is the line you want to modify so the application behaves the way you want.
}
}
Step 2 - Override the default Fortify Login Response
In this step you have to tell Laravel to use your login response instead of the default Fortify response.
<?php
namespace App\Providers;
use App\Http\Responses\LoginResponse;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(
LoginResponseContract::class, // Contract is required in order to make this step work.
LoginResponse::class,
);
}
//...
}
Once you're done making the changes the user will be redirected to wherever you set it to be.
There is a simpler solution to this.
If you look in config/fortiy.php you will see the home variable is set to:
'home' => RouteServiceProvider::HOME,
This refers to a public const variable in app/Providers/RouteServiceProvider.php
So to redirect users to the home page after they login you can simply change the home variable:
public const HOME = '/';
Doing it this way is slightly less complex and saves you having to create a whole new login response class.
If the changes don't take effect straight away try running:
php artisan optimize
Just open fortify in the config folder
Search for 'home' => RouteServiceProvider::HOME
and replace it but your code logic and don't forget to add Auth facades
use Illuminate\Support\Facades\Auth;
like is :
'home' => function () {
$is_active = Auth::user()->is_active;
$role = Auth::user()->role;
if ($is_active == 1) {
if ($role== 1) {
return '/admin/dashboard';
} else {
return '/';
}
} else {
return '/login';
}
},
I liked Matrix Admin panel, so i started implementing it. I didnt like the option of having admin in User model (boolean check isAdmin), so i created a separate model called Admin. I set up all the routes, and it worked in my test admin page with the following routes:
web.php
Route::get('/admin/login', 'Auth\AdminLoginController#showLoginForm')-
>name('admin.login');
Route::post('/admin/login', 'Auth\AdminLoginController#login')-
>name('admin.login.submit');
Route::get('/admin', 'AdminController#index')->name('admin.admin');
This is my AdminLoginController:
public function showLoginForm()
{
return view('admin/admin-login');
}
protected function guard(){
return Auth::guard('admin');
}
use AuthenticatesUsers;
protected $redirectTo = '/admin/login';
public function __construct()
{
$this->middleware('guest:admin')->except('logout');
}
And my AdminController:
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
return view('admin.admin');
}
I call routes in the view like this:
href="{{ route('admin.login') }}"
For some reason, it doesn't log me out and get me to the login page, instead it just refreshes the page, hence returns me to the /admin page with the admin logged in. What am i missing here? Thanks for all replies.
In the constructor for the AdminLoginController, you have set the middleware to be 'guest:admin'.
This uses the guest middleware that is defined in /app/Http/Middleware/RedirectIfAuthenticated.php by default, or configured in /app/Http/Kernel.php
The $guard string passed for it to use is 'admin'.
I'm guessing that you provide an implementation for this admin guard.
Supposing that you're logged in as an admin, navigating to route('admin.login')
will redirect your request to '/home' in the default implementation;
there are likely chances that there exists a custom redirection to /admin in your implementation.
If you like to logout of the session, you can register a route for the logout method provided in Illuminate\Foundation\Auth\AuthenticatesUsers trait.
Route::get('/admin/logout', 'AdminController#logout')->name('admin.logout');
Since the AuthenticatesUsers::logout redirects to / by default, I'm guessing you need to override this behavior.
You can do exactly that by providing a custom implementation for AuthenticatesUsers::loggedOut in your controller.
protected function loggedOut(Request $request)
{
return redirect('/admin');
}
Finally, provide this route for the href in your link {{ route('admin.logout') }}
It's all about session,
\Auth::logout();
$request->session()->invalidate();
Laravel 5.2 has been out for some time now. Yes, it has new auth function which is very good. Specially for beginners.
My question,
How to check if user is admin and then redirect safely to admin/dashboard properly? I know one way is to use admin flag in database but can any of you show some example?
go to AuthController.php and add this method
where role is the user role as defined in the database.
protected function authenticated($request,$user){
if($user->role === 'admin'){
return redirect()->intended('admin'); //redirect to admin panel
}
return redirect()->intended('/'); //redirect to standard user homepage
}
As in Laravel 5.3 / 5.4
Add following line to create_users_table migration.
$table->boolean('is_admin');
Add following method to LoginController.
protected function authenticated(Request $request, $user)
{
if ( $user->is_admin ) {
return redirect('/admin/home');
}
return redirect('/home');
}
Additional note don't forget to add the following lines to RedirectIfAuthenticated middleware:
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
// the following 3 lines
if (Auth::user()->is_admin) {
return redirect('/admin/home');
}
return redirect('/home');
}
return $next($request);
}
Otherwise if you e.g. type yourdomain/login and your logged in as admin it would be redirected to home instead of admin/home.
AuthController extends the AuthenticatesAndRegistersUsers trait, which has a public method named redirectPath. In my case I would extend that method on the AuthController and I'd put my logic there:
public function redirectPath()
{
if (Auth::user->myMethodToCheckIfUserHasAnAdminRoleLikeAnEmailOrSomethingLikeThat()) {
redirect('admin/dashboard');
}
redirect('home');
}
in Auth/LoginController there is protected $redirectTo = '/home';
change '/home' to '/loginin' for example, and create a new controller and in the controller get the information of the user and check if he is a admin or not and then redirect him to the proper page
I'd like to redirect my user to different route, based on their role. I have two secured area in my app, "admin" and "dashboard". I'd like to check if user is authenticated, then redirect to intended, but if user has role editor it should be redirected to dashboard, otherwise if he has role admin should be redirected to admin area.
I'm using AuthenticatesAndRegistersUsers class in my login. I have this on my custom controller:
/**
* The default redirecTo path.
*
*/
protected $redirectTo = '/dashboard';
So when a user is authenticated it will be redirected to dashboard, but I'd like to check if the intended url is on admin group route and if user has admin role it should be redirected to admin area.
I'm using this middleware to redirect to login:
public function handle($request, Closure $next)
{
if ($this->auth->guest())
{
if ($request->ajax())
{
return response('Unauthorized.', 401);
}
else
{
return redirect()->guest('auth/login');
}
}
return $next($request);
}
You could overwrite the redirectPath method used by the trait in your AuthController to inject the logic you need. Something like this:
/**
* Get the post register / login redirect path.
*
* #return string
*/
public function redirectPath()
{
// Logic that determines where to send the user
if (\Auth::user()->type == 'admin') {
return '/admin';
}
return '/dashboard';
}
EDIT:
Laravel uses the following declaration in the AuthenticatesAndRegistersUsers trait to redirect the user after successful login:
return redirect()->intended($this->redirectPath());
This will try to redirect the user to the previously attempted URL.
If you need to redirect users to the right place when they're already logged in, that would be best done by adding more logic to your authentication middleware.
Another approach is to override authenticated method
public function authenticated()
{
if(Auth::check()) {
if(\Auth::user()->hasRole('Super Admin')) {
return redirect('/admin-dashboard');
} else {
return redirect('/user-dashbaord');
}
}
}
I use this one. You also need to modify middleware RedirectIfAuthenticated so that it won't route home. Just to different user's dashboard.
public function authenticated()
{
if($request->user()->hasRole('admin'))
{
// return redirect()->intended(route('admin.index'));
return redirect()->route('admin.index');
}
if($request->user()->hasRole('super'))
{
return redirect()->route('super.index');
}
if($request->user()->hasRole('officer'))
{
return redirect()->route('officer.index');
}
}