Custom Guard Authentication Exception - laravel

I created a custom guard (admin) in my application, and everything looks good following this tutorial online (https://pusher.com/tutorials/multiple-authentication-guards-laravel). The only problem is when i try to access a view that is protected by the admin guard, instead of giving me a exception NotAuthenticate, is giving me a "InvalidArgumentException
Route [login] not defined.".
My Dashboard controller custom guard is:
public function __construct()
{
$this->middleware('auth:admin');
}
But the strange thing that i cant understand whats going on is that when i add in my web.php routes the "Auth::routes();", it works fine, the Exception NotAuthenticate gets fired.
Is there a reason why my custom only works has expected with i add the Auth::routes() ?
Admin Login Controller:
namespace App\Http\Controllers\Admin\Auth;
use Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/admin/dashboard';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest:admin')->except('logout');
}
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
public function showLoginForm()
{
return view('admin.auth.login');
}
/**
* Log the user out of the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->invalidate();
return $this->loggedOut($request) ?: redirect('/admin');
}
/**
* Get the guard to be used during authentication.
*
* #return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('admin');
}
}

Try following the following tutorial, it did the trick for me.
On a side note: Avoid modifying the existing controller that laravel ships with, instead extend it and implement your own functionality. This practice will take you the long way.
https://www.codementor.io/okoroaforchukwuemeka/9-tips-to-set-up-multiple-authentication-in-laravel-ak3gtwjvt

Related

laravel authentication redirect

I'm new to Laravel and have just added the Authentication package to an existing project.
Upon logging in, I want to be redirected to /Result a page that that I know works using a controller. If I type the URL /Result the page loads correctly but when I login I am being redirected to index each time rather than /Result
Routes
Route::get('/result','ResultsController#getResults')->name('result');
Auth::routes();
Route::get('/', 'HomeController#index')->name('/');
Home Controller
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('result');
}
}
Results Controller
class ResultsController extends Controller
{
public function getResults( )
{
$results = Result::all();
return view('/result', ['results' => $results]);
}
}
Login Controller
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = 'result';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
/**
* #return
*/
public function authenticated()
{
return redirect()->route('result');
}
}
So far I can load index and be redirected to login, when I login I want to be redirected to /Result but instead I recieve an Undefined variable: results.
I have jumped to /Results by manipulating the URL and the page /Results does work.
Any help would be much appreciated, just le me know if you need any additional code examples from any other files.
thanks
James
First of all change the route name format use only result.
Route::get('/result','ResultsController#getResults')->name('result')
For redirect any route you can use LoginController authenticate method.
\App\Http\Controllers\Auth\LoginController.php
Add this method to that controller:
/**
* #return
*/
public function authenticated()
{
return redirect()->route('result');
}

Prevent login to user and custom guards at the same time

I am using a custom guard for a different type of user using a custom guard labelled business_user.
I have noticed I am able to login to as both normal users (web) and my business_users.
I've read in the Pusher documentation that I used to create my custom guards in the first place to add additional middleware into my "LoginController".
But I don't actually even have a LoginController, I've created my own controllers for each user type. AuthController (for web) and BusinessController (for business_user).
I have created a third controller labelled LoginController with the following code:
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = '/dashboard';
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->middleware('guest:business_user')->except('logout');
}
}
I also updated my RedirectIfAuthenticated as follows:
class RedirectIfAuthenticated
{
public function handle($request, Closure $next, $guard = null)
{
if ($guard == "business_user" && Auth::guard($guard)->check()) {
return redirect('/dashboard');
}
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
I also have a RedirectIfAuthenticated middleware inside my Middleware folder.
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if ($guard == "business_user" && Auth::guard($guard)->check()) {
return redirect('/dashboard');
}
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
}
When I land on my user login page, it still allows me to attempt logging in. Can someone tell me how to resolve this?
In LoginController, you can override authenticated method.
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
auth()->login($user); // this method will login with default guard
return redirect()->intended($this->redirectPath());
}
I think because the order of middleware
<?php
public function __construct()
{
$this->middleware('guest')->except('logout'); // this procress first and redirect to login page
$this->middleware('guest:business_user')->except('logout');
}
So, I think you can check directly in __construct() of LoginController or in login view (blade file)
#if (Auth::check('business_user'))
You are already logged in (or perform a redirect somewhere)
#else
//display login form
#endif

Laravel custom guard remember me function not working with AuthenticateUser trait

I created a second guard name customer that uses the AuthenticatesUsers trait everything seems to work well except the remember me function every time i login i can't seem to log out. So i think the remember me is using the default guard so how do i fix this issue? Can i fix the issue in the login controller?
customer login controller
<?php
namespace App\Http\Controllers\CustomerAuth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Auth;
use App\Customer;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
protected function guard()
{
return Auth()->guard('customer');
}
public function showLoginForm()
{
if(Auth::user() || Auth::guard('customer')->user())
{
return redirect('/');
}
else{
return view('customer-auth.login');
}
}
}
AuthenticateUser.php
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
I use a few custom guards. I had to make a new logout method that uses
\Auth::guard($guard)->logout();
since by default the logout() method in StatefulGuard.php does not accept any parameters like a guard.

How do I pass data from LoginController to my HomeController?

I want to pass my input information ($request->all()) from my LoginController to my HomeController. How can I do that? The LoginController is generated by Laravel scaffold.
LoginController:
<?php
namespace App\Http\Controllers\Auth;
use \Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Auth\Authenticatable;
use Illuminate\Http\Request;
use App\Account;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct(Request $request)
{
$this->middleware('guest', ['except' => 'logout']);
}
/**
* Override the username method used to validate login
*
* #return string
*/
public function username()
{
return 'username';
}
}
HomeController in which dd($request->all() returns []
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Blog;
use App\Account;
use Illuminate\Foundation\Auth;
use Illuminate\Support\Facades\Input;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
//$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$blogItems = Blog::all();
$onlinePlayers = Account::getOnlinePlayers()->count();
$onlineStaff = Account::getOnlineStaff()->count();
//return view('home.index', compact('blogItems', 'onlinePlayers', 'onlineStaff'));
return dd($request->all()); //This returns an empty array
}
}
Quick and dirty
The following method is a quick and dirty method. It relies on how Laravel's authentication is designed under the hood. If Laravel changes this in the next version, this may need to change with it.
In your LoginController, implement your own login() method. You will need to rename the login() method provided by the trait because we still want to call it:
class LoginController extends Controller
{
use AuthenticatesUsers {
login as traitLogin
}
public function login(Request $request)
{
$request->session()->flash('form_type', 'login');
return $this->traitLogin($request);
}
}
In your RegisterController, implement your own register() method. You will need to rename the register() method provided by the trait because we still want to call it:
class RegisterController extends Controller
{
use RegistersUsers {
register as traitRegister
}
public function register(Request $request)
{
$request->session()->flash('form_type', 'register');
return $this->traitRegister($request);
}
}
Now, in your HomeController, you can get the type of form that was submitted from the flashed session data.
class HomeController extends Controller
{
public function index(Request $request)
{
$form = $request->session()->get('form_type');
// the rest of your logic
}
}
Cleaner
In contrast to the method above, I would suggest using a hidden form value and a new middleware to process that form value.
This is a little bit cleaner because it doesn't rely on any of the built in Laravel authentication logic. If Laravel changes the name of the traits, the method names, the route actions, or the actual logic used inside the methods, it won't affect how this functionality is designed or how it works.
In your login and register forms, add a new hidden field:
Login form:
<input type="hidden" name="form_type" value="login" />
Register form:
<input type="hidden" name="form_type" value="register" />
Now, create a middleware that will process this new form element and flash the value to the session.
class FlashFormType
{
public function handle($request, Closure $next)
{
$response = $next($request);
if ($request->has('form_type')) {
$request->session()->flash('form_type', $request->input('form_type'));
}
return $response;
}
}
From here, you can either add this middleware to the web middleware group in app/Http/Kernel.php so it is used for all web requests, or you could just add this middleware to the LoginController and RegisterController constructors so that only they use it.
Once you've assigned the middleware somewhere, update your HomeController to access your flashed data:
class HomeController extends Controller
{
public function index(Request $request)
{
$form = $request->session()->get('form_type');
// the rest of your logic
}
}
NB: none of the provided code is tested. treat as pseudo-code.
If you want to get current user, that was authenticated with your login data, then \Auth:user() will go the trick. Here is index() of HomeController:
public function index()
{
return \Auth::user();
}
If you really need input data (actually I cannot imagine the case) , a solution may be to put request->all() in session session(['login_data' => $request->all() ]) and then retrieve it via session('login_data'). If you go that way, add this method to your LoginController:
/**
* Send the response after the user was authenticated.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
session(['login_data' => $request->all() ]);
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended($this->redirectPath());
}
This overrides original sendLoginResponse() method of AuthenticatesUsers trait. Then in HomeController put this:
public function index()
{
return session('login_data');
}
Hope this helps!

Declaration of App\Http\Requests\Comment\CreateRequest::authorize() should be compatible with App\Http\Requests\Request::authorize()

Hello im creating i comment system for my laravel app but i get this error when i try to comment.. basically when a user is not logged in and he tries to comment and submit it, it should redirect him to the login page, so my CreateRequest file is this
<?php
namespace App\Http\Requests\Comment;
use App\Http\Requests\Request;
use App\Repositories\Image\ImageRepository;
class CreateRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #param ImageRepository $image
* #return bool
*/
public function authorize(ImageRepository $image) {
$image = $image->getById($this->route('id'))->first();
if (!$image) {
return false;
}
return auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules() {
return [
'comment' => ['required', 'min:2'],
];
}
/**
* #return \Illuminate\Http\RedirectResponse
*/
public function forbiddenResponse() {
return redirect()->route('login');
}
}
and my App\Http\Requests\Request file is this
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest {
public function authorize() {
return true;
}
}
if i remove
public function authorize() {
return true;
}
then comments works and if user is not logged in the user gets redirected to the login page but then my login is not working and i get Forbidden when i try to login
im developing my app on top of this project https://github.com/laravelish/EasyAdmin
Hope someone can help me
You've defined an authorize method in your abstract Request class:
public function authorize() {
return true;
}
Note it doesn't take any parameters. Now if you extend this abstract class (like you are doing with CreateRequest) and you write an authorize method, you must use the same signature. Specifically: authorize can't take any parameters, because it doesn't in the abstract class.
If you were to remove the authorize method from your abstract class, this specific error would go away. However I'm not sure that would solve your problem. I don't think Laravel provides dependency injection for the authorize method, you can't just inject your repository like that.
This is one way to fix both issues:
public function authorize() {
$image = app(ImageRepository::class)->getById($this->route('id'))->first();
...

Resources