Get authentication data inside of Constructor issue in Laravel5.3.19 - authentication

I have upgrade Laravel from 4.2 to laravel5.3 but I can't access Authentication data inside of Constructor of Controller
I have as below Middleware but it never work for me
use App\Http\Controllers\BaseController;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Redirect;
use Auth;
use App\User;
class DashboardController extends BaseController
{
public $user;
public function __construct(Guard $guard, User $user)
{
$this->middleware(function ($request, $next) {
$this->user = Auth::user();
return $next($request);
});
//$this->userID = Auth::user()?Auth::user()->id:null;
dd($user);// Result attributes: []
dd($guard);
dd($this->user);
}
}
The result after DD()
dd($guard);
DD($this->user);
NULL
It will return Null when I dd user property.

This is to be expected. The reason you have to assign the user inside the middleware closure is because the session middleware hasn't run yet. So, the closure you have above won't actually be called until later in the execution process.
If you move the dd($this->user) to inside the middleware closure or in to your one of you route methods in that controller it should be working absolutely fine.
Also, just FYI, in your middleware closure you can get the user instance from the request i.e. $request->user() will give you the authenticated user.
Hope this help!

Related

Call to a member function addUnauthenticatedActions() on null (CakePHP Authentication)

I am trying to implement the CMS Tutorial - Authentication for CakePHP and I am only trying to implement the login page up till now but it is giving me an error on this line
$this->Authentication->addUnauthenticatedActions(['login']);
Error:
Call to a member function addUnauthenticatedActions() on null
UsersController:
public function beforeFilter(\Cake\Event\EventInterface $event){
parent::beforeFilter($event);
// Configure the login action to not require authentication, preventing
// the infinite redirect loop issue
$this->Authentication->addUnauthenticatedActions(['login']);
}
public function initialize() :void{
$this->loadComponent('Flash');
$this->loadComponent('Authentication.Authentication');
}
in your appController use $this->Authentication->addUnauthenticatedActions(['someactions']);
and if you want to use UnauthenticatedActions in your controller you nit to put
public function beforeFilter(EventInterface $event)
{
parent::beforeFilter($event);
$this->Authentication->allowUnauthenticated(['actions']);
}

Problems on testing middleware in Laravel with Clousure $next

I have this middleware on my app that checks the user role for a route:
public function handle($request, Closure $next, ...$roles)
{
if (in_array($request->user()->rol, $roles)) {
return $next($request);
} else {
return redirect()->action('SecurityController#noAutorizado');
}
}
And I'm triying to make a test for this middleware (phpUnit):
public function testUsuarioLogadoPuedeAccederAPantallaUsuarios()
{
$user = UsuariosTestFixtures::unAsignador();
$this->actingAs($user);
$request = Request::create('/usuarios', 'GET');
$middleware = new CheckRole();
$response = $middleware->handle($request,Closure $next,$user->getRole(), function () {});
$this->assertEquals($response, true);
}
But i'm retreiving this error: Argument 2 passed to App\Http\Middleware\CheckRole::handle() must be an instance of Closure, null given
I don't know how I have to pass the "Closure $next" on the $middleware->handle
I've tryed this:
public function testUsuarioLogadoPuedeAccederAPantallaUsuarios(Closure $next){...}
But It returns an error: Too few arguments to function UsuarioControllerTest::testUsuarioLogadoPuedeAccederAPantallaUsuarios(), 0 passed in C:\www\APPS\catsa\vendor\phpunit\phpunit\src\Framework\TestCase.php
What's the solution?
Thanks a lot!
A Closure in PHP is simply a function, so you need to pass a function as the second argument of your handle method.
In the context of Laravel middleware, the $next function represent the full pipeline of steps that the request goes through.
Obviously you can't (and don't need to) execute this pipeline during a test. What you need is just a function that return some values that your can test in an assertion.
What you can do is something like this:
//... setup code here
$middleware = new CheckRole();
$roles = ['role1', 'role2']; // change this with the desired roles
$result = $middleware->handle($request,function($request) {
return 'success';
},$roles);
$this->assertEquals('success', $result);
So, what is happening here?
If everything goes as planned (the user has the required role), the $next closure is executed and it returns success; on the other hand, if the user doesn't have the required role, the code takes the other path and it returns a RedirectResponse.
Finally, the assertion checks if success is returned, and it reports a failure if that doesn't happen.

Redirect user after login in laravel 5.1

I am trying to implement a feature where, after logging in, a user gets redirected to a URL depending on their role. I have the roles part set up, but I'm having trouble testing the user's properties immediately after login.
I followed the instructions here to create a user login page. I have an AuthController that looks like this:
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller {
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected $redirectTo = '/test';
...
}
My __construct() function validates the user, but I don't know how to access the user object only immediately after login. This is what I presently have:
public function __construct() {
$this->middleware('guest', ['except' => 'getLogout']);
if ( \Auth::check() ) {
$user = \Auth::user();
if ( $user->admin() ) {
// an admin
$this->redirectTo = '/admin';
} else {
// it's a client
$this->redirectTo = '/client/dashboard';
}
}
$user = \Auth::user();
if ( is_object($user) ) {
} else {
$this->redirectTo = '/auth-not-object';
}
}
When I first attempt to log in with an administrator account, I get to the path /auth-not-object, because there isn't any authenticated user object at that point.
After having attempted to log in, but getting a bad redirect, when I revisit the /login url, I get redirected to /home, which I believe is the default $redirectTo in the traits this class uses. So that means we've passed the AuthController __construct() method without having changed the $redirectTo, even though there is an authenticated user.
I've found other questions, such as How to add extra logic on login condition in Laravel 5.2 and laravel redirect to url after login, but I don't understand how to apply those answers. For instance, the accepted answer to the second question shows new methods, getCredentials() and login(), which don't exist in the poster's original class. I am not sure in what class to add them, or where to call them from, in my codebase.
Other similar answers show a radically different way of authenticating users, such as this. It seems that, to use that solution, I would need to re-write my code, and forgo the use of the traits, which include bonus features like login throttling and so on.
Is there a way I can redirect users based on role after login, while still using these built-in traits?
Im not sure if the 5.1 auth is the same as the 5.2 auth, but if it is, remove all that from the construct and add this method:
protected function handleUserWasAuthenticated( Request $request, $throttles, $guard )
{
if ($throttles) {
$this->clearLoginAttempts( $request );
}
if ( method_exists( $this, 'authenticated' ) ) {
return $this->authenticated( $request, Auth::guard( $guard )->user() );
}
return redirect()->intended( $this->redirectTo );
}
this is the method that will determine the redirect and you have access to the user object.
EDIT
I take the above back, just add the following to your controller;
protected function authenticated( $request, $user ) {
return redirect()->intended( $user->admin() ? '/admin' : '/client/dashboard' );
}
That should work nicely

LARAVEL 5: Need to keep query string after auth redirects

I have a link I am sending via email. For example, www.swings.com/worker?id=3382&tok=jfli3uf
In this case I want the person to click the link, get sent to the login page(which it does) and then be directed to a controller method WITH the $id and $tok variables. I can't get that part to work. Any ideas? I am only using the RedirectIfAuthenticated class and this is what it looks like:
public function handle($request, Closure $next)
{
$user = $request->user();
if ($this->auth->check()) {
if($user && $user->hasRole('worker'))
{
return redirect('worker');
}
return redirect('home');
}
return $next($request);
}
hasRole is a method I created in the User model that checks the role of the logged in user
You can flash data to the session when redirecting by chaining the with() method:
// in your handle() method:
return redirect('home')->with($request->only('id', 'tok'));
// then in home controller method:
$id = session('id');
$tok = session('tok');
AFTER SOME HOURS I WAS ABLE TO HAVE A SOLUTION:
ReturnIfAuthenticated wasn't changed. I just added the following within my controller that this link should go to:
for instance, the route would be:
Route::get('worker', 'WorkerController#methodINeed');
Within this method:
public function methodINeed() {
$id = Input::get('id');
$tok = Input::get('tok');
// Do what I need this variables to do
}
What I didn't understand and what could not be properly understood is that the auth controller in Laravel 5 is triggered when a user is a guest it will still redirect to the actual method with all its original data once auth is successful. Hope this is helpful.

Authentication views for Laravel 5.1

Laravel 5.1 has just been released, I would like to know how could I tell the AuthController to get the login & register view from a custom directory? the default is: resources/views/auth...
The trait AuthenticateAndRegisterUsers only has this:
trait AuthenticatesAndRegistersUsers
{
use AuthenticatesUsers, RegistersUsers {
AuthenticatesUsers::redirectPath insteadof RegistersUsers;
}
}
The code you're showing there only fills one function: it tells our trait to use the redirectPath from the AuthenticatesUsers trait rather than the one from RegistersUsers.
If you check inside the AuthenticatesUsers trait instead, you will find a getLogin() method. By default, this one is defined as
public function getLogin()
{
return view('auth.login');
}
All you have to do to get another view is then simply overwriting the function in your controller and returning another view. If you for some reason would like to load your views from a directory other than the standard resources/Views, you can do so by calling View::addLocation($path) (you'll find this defined in the Illuminate\View\FileViewFinder implementation of the Illuminate\View\ViewFinderInterface.
Also, please note that changing the auth views directory will do nothing to change the domain or similar. That is dependent on the function name (as per the definition of Route::Controller($uri, $controller, $names=[]). For more details on how routing works, I'd suggest just looking through Illuminate\Routing\Router.
for those who is using laravel 5.2, you only need to override property value of loginView
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
public function showLoginForm()
{
$view = property_exists($this, 'loginView')
? $this->loginView : 'auth.authenticate';
if (view()->exists($view)) {
return view($view);
}
return view('auth.login');
}
so to override the login view path, you only need to do this
class yourUserController {
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
.....
protected $loginView = 'your path';
}