Change LogIn route - laravel

I am working in Laravel auth application and when my user is log out I want to redirect it to custom static page and from there I want to redirect to login page again by clicking button on that page.
For example when user is trying to access some particular route, and he is unauthorized then I want to redirect with satatic.blade.php and from there I want to redirect it to log in page, How can I make it happen?

As you didn't mention which Laravel version you are using and which scaffolding you are using, I am assuming you are using Laravel 5.5/6 with LaravelUI/default auth scaffolding.
You should have App\\Http\\Controllers\\Auth namespace where you kept all auth related controller.
You should have one LoginController.php which contains all default login behavior inside AuthenticatesUsers trait. We should override the login method inside our controller.
Copy this code to your LoginController class to do so.
public function login(Request $request)
{
$this->validateLogin($request);
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
// Here is our custom logic check occurs before login
if ($this->userIsnotAuthorized()) { // All your logic checks are inside 'userIsnotAuthorized()' method. Use any function or static check here
return redirect()->to('/static/page'); // Also can use route name / url
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
EDIT #1
If you want to have the same check for all protected routes, you should generate a middleware with php artisan make:middleware CheckResourceAccessMiddleware and use the same in your route.
In CheckResourceAccessMiddleware's handle method
// Here is our custom logic check occurs before login
if ($this->userIsnotAuthorized()) { // All your logic checks are inside 'userIsnotAuthorized()' method. Use any function or static check here
return redirect()->to('/static/page'); // redirect to static page which indicates unauthorized user note
}
return $next($request); // proceed to your page as user is authorized
to register the middleware edit your app/Http/Kernel.php and add this line to $routeMiddleware array
protected $routeMiddleware = [
...
'resource_access' => \App\Http\Middleware\CheckResourceAccessMiddleware::class,
];
After this step., you can use the middleware in any routes you want to protect
Route::get('/protected', [Controller::class, 'method'])->middleware('resource_access');
OR
// Middleware will be applied to all routes inside it
Route::middleware('resource_access')->group(function () {
Route::get('/protected', [Controller::class, 'method']);
// all other protected routes will be here
});

I found different approaches for this problem, Later I Found the best solution, as mention below,
In App\Middlewear\Authenticate.php, I have to change from return route('login');
to return route('my_custom_page_route');
From my custom page I can redirect it to auth login page easily.
Thank you everyone who suggest the best solutions.

Related

Laravel 8 jetstream stack inertia. Redirect to Home after Login, instead of users choice

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';
}
},

Laravel Routing Order Multiple "Homepages" Based On Auth

I have a Laravel routing file (web.php) like so:
Route::group(['middleware' => ['auth']], function () {
Route::get('/', function () {
return 'Hello World';
});
});
Route::get('/', 'Auth\LoginController#showLoginForm')->name('login');
In my application the unauthenticated homepage must go to the login screen. When authenticated, the homepage changes. However, if I run this code and login - I get an infinite redirect because the LoginController has this line:
protected $redirectTo = '/';
So basically, even thought Laravel should read the routes file top to bottom, it seems this isn't applying in my case (maybe because of the ::group()) or I am doing something wrong.
How can I accomplish a homepage that goes to the login form while also redirecting back to the same url (/) for authenticated users for a different authenticated view (and no redirect loop).
Thanks!
I would handle this inside a guest middleware that checks for an authenticated user. For this case you'll want an authenticated guard check first:
use Illuminate\Contracts\Auth\Guard;
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return redirect('/home');
}
return $next($request);
}
Apply the guest middleware to the login endpoint:
Route::get('/', 'Auth\LoginController#showLoginForm')
->middleware('guest')
->name('login');
Note: Only apply the guest middleware to guest routes, otherwise you run the risk of redirect loops.
Why not handle this in your view?
You can simply remove one of the route declaration from your web.php.
Then go ahead with conditional rendering.
#auth
Show Home page
#endauth
#guest
Show Login
#endguest
I guess middleware does not prevent request from hitting the routes,
It rather prevents request from going through.
You can't use middleenter code hereware to decide with route to hit, thereby the loop.
When you're thinking in terms of bottom down processing, laravel has already registered every declared routes.

Redirect to origin page that requested the login in Laravel

I have searched all over the place, none of the answers was to my needs.
I have a Laravel app, with various pages that require the user to be logged in.
The normal redirect in Laravel after login is to the home page.
How can I make a redirect to the original page that requested the login?
For example:
A user tries to go to example.com/page/1 that is for authenticated users only. He is redirected to the login page, submit the form and then redirects to the home page. How can I redirect him back to example.com/page/1 or whatever page that he came from?
You can use intended method for this purpose, From the docs:
The intended method on the redirector will redirect the user to the
URL they were attempting to access before being intercepted by the
authentication middleware. A fallback URI may be given to this method
in case the intended destination is not available.
In your Login Controller add the below code:
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
You could potentially hook in to Laravel's intended() method. Usually, this would be a guarded route that a user tried to access before they were redirected to the login page but you can manually set it to what ever you want it to be.
In your LoginController add the following:
public function showLoginForm()
{
if (!session()->has('url.intended')) {
redirect()->setIntendedUrl(session()->previousUrl());
}
return view('auth.login');
}
This will check to see if the intended url is set, if it isn't it will set it to the previous url.
in your LoginController :
protected function authenticated(Request $request, $user) {
return redirect()->back();
}

Cant logout from custom Admin Panel Laravel 5.7

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();

Implementing native multi auth (user vs admin) using guards in Laravel 5.5 - guest middle ware uses hard coded named route

I would like to implement native multi authentication in my application for two types of users: User and Admin.
I started implementing a new admins table migration (by copying the existing create_users_table).
I created a new model called Admin (by copying the existing User model)
Both (User and Admin) models were updated to specify which guards they use like this:
User Model
protected $guarded = ['user'];
Admin Model
protected $guarded = ['admin'];
Then I setup the auth configuration like this:
config/auth.php
https://pastebin.com/iLAZbX2z
Then I defined my custom auth routes for users and admins like this:
routes/web.php
https://pastebin.com/raw/CKX9Xddb
Finally, I defined the auth protected routes for the two user types like this:
routes/web.php
// User auth protected pages
Route::prefix('manage')->middleware('auth:user')->namespace('Manage')->group(function() {
Route::get('/', 'DashboardController#index');
});
// Admin auth protected pages
Route::prefix('admin')->middleware('auth:admin')->namespace('Admin')->group(function() {
Route::get('/', 'DashboardController#index');
});
I tested the user login first before proceeding (there's more to be done to get admin to login), by going into http://myapp.local/login and entering my credentials and I was successfully redirected to user's dashboard (i.e. http://myapp.local/manage). All of the user specific functionality (e.g. reset pass) etc.. are all working fine).
However; when testing the guest middleware by visiting http://myapp.local/manage directly, I expected to be redirected to http://myapp.local/login but got an error instead:
Route [login] not defined.
This error is valid; because in the routes definition, I've named the user login as user.login
It looks like the guest middleware uses a hard coded named route called login in the unauthenticated exception handler.
vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php
protected function unauthenticated($request, AuthenticationException $exception)
{
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest(route('login')); // <------
}
How can I tell the guest middleware to use a differently named route for the login (when un-authenticated user tries to visit a auth protected page)?
I will need to use this later for the admin guest middleware also.
Thanks to Sohel0415's answer; I realised that the App\Exceptions\Handler extends the vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php, which means I can solve it like this:
I've edited the app\Exceptions\Handler.php like this:
Included this use statement at the top:
use Illuminate\Auth\AuthenticationException;
Added this method:
https://pastebin.com/raw/10Y1tS6d
I've named the user login as user.login
You're getting the error because the route name is user.login and you're trying to use login route. So, use proper route name here:
redirect()->guest(route('user.login'));
Use Request::is() to check the requested url, then redirect :
protected function unauthenticated($request, AuthenticationException $exception)
{
if(\Request::is('manage/*')){
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest(route('user.login'));
}
else if(\Request::is('admin/*')){
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest(route('admin.login'));
}
else{
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest(route('login'));
}
}
Note: add this method in App\Exceptions\Handler

Resources