Laravel 5.2 : How to call "sendFailedLoginResponse" from custom Login Event Handler? - authentication

In Laravel 5.2, there is a function already overriden in my AuthController.php:
public function sendFailedLoginResponse()
{
$errors = new MessageBag([
'email' => ['Error message for email'],
'password' => ['Error message for password'],
'mycustominput' => ['Error message for my custom input field'],
]);
return redirect()->back()->withErrors($errors);
}
This alone works (like magic) via normal FAILED login attempts. (When login is failed, the login form already shows this custom error messages, instead of the default ones. So this is getting triggered. So is ok.)
Now i have below Custom Login Event Handler, registered in the EventServiceProvider.php:
'Illuminate\Auth\Events\Login' => ['App\Listeners\UserLoggedIn']
And then, i wanna TRIGGER the overridden function sendFailedLoginResponse() from this Custom Login Event Handler. Something like:
app/Listeners/UserLoggedIn.php:
// Some codes at top
public function handle(Login $event)
{
// Some coding ..
// Some custom verifications ..
if ( $customLoginCheck == false )
{
????::sendFailedLoginResponse(); // <----- Here call/trigger the method!
}
}
When i tried using Auth::sendFailedLoginResponse(), it gives me following errors:
ErrorException in AuthManager.php line 288:
call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\Auth\SessionGuard' does not have a method 'sendFailedLoginResponse'
Because i do NOT know "how" to call that desired function from a Custom Event Handler. (And also don't know what are the required includes.)
Please help to suggest. (Thanks all)

Related

RxJs: How to conditionally chain observable of BehaviorSubject?

I've got an observable data service (UserService) that returns the currently logged in user. I followed this tutorial - https://coryrylan.com/blog/angular-observable-data-services, which describes using a BehaviorSubject to return a default currentUser immediately, then emit the real currentUser once it's loaded or altered. The service is basically like this...
private _currentUser: BehaviorSubject<User> = new BehaviorSubject(new User());
public currentUser: Observable<User> = this._currentUser.asObservable();
constructor(private http: Http) {}
loadUser() { // app.component onInit and login component call this
return this.http.get('someapi.com/getcurrentuser')
.map(response => <User>this.extractData(response))
.do(
(user) => {
this.dataStore.currentUser = user;
this._currentUser.next(Object.assign(new User(), this.dataStore).currentUser);
},
(error) => this.handleError(error)
)
.catch(error -> this.handleError(error));
}
I'm having problems whenever a user hits F5 to reload the entire spa. When a consuming component subscribes to the currentUser on the UserService, it immediately receives a default user while the UserService waits for an api call to receive the actual user. The moment that api call finishes, the real user is emitted by UserService and all the subscribers get the real user. The first value emitted by the BehaviorSubject, however, is the default value and it always has an id of "undefined", so we can't make our next api call yet. In fact, when the real user comes through and I CAN make a valid call using the user.id, the chained subscription never happens and I don't get the values out of the response.
I know I'm doing something stupid, but I haven't figured out exactly what yet. I just stumbled across concatMap, but I'm not sure how to use it. While I pursue that, I'd like to know why the below code doesn't work. I particularly want to know why the subscribe never fires, even after the real user comes in, just to help my newbie understanding of Observables.
this.userService.currentUser
.flatMap((user) => {
this.user = user;
// Need to NOT call this if the user does not have an id!!!
this.someOtherService.getSomethingElse(user.id); // user.id is always undefined the first time
})
.subscribe((somethingElse) => {
// This never gets called, even after the real user is emitted by the UserService
// and I see the getSomethingElse() call above get executed with a valid user.id
this.somethingElse = somethingElse;
});
If you want to ignore user instances that do not have an id, use the filter operator:
import 'rxjs/add/operator/filter';
this.userService.currentUser
.filter((user) => Boolean(user.id))
.flatMap((user) => {
this.user = user;
this.someOtherService.getSomethingElse(user.id);
})
.subscribe((somethingElse) => {
this.somethingElse = somethingElse;
});
Regarding "why the subscribe never fires", it's likely due to an error arising from the undefined id. You only pass a next function to subscribe, so any errors will be unhandled. And if an error occurs, the observable will terminate and will unsubscribe any subscribers - as that is how observables behave - so any subsequent users with defined id properties will not be received.

Overriding Login Error Messages

I have an AuthController, where I have extended the getCredentials method so the user needs to be both existant and active to be able to login. This is the method:
protected function getCredentials(Request $request) {
$credentials = $request->only($this->loginUsername(), 'password');
return array_add($credentials, 'status', '1');
}
I would also like the failed login messages to be different, depending on whether or not the user is active, so the user knows if he is failing his username / password, or just because he hasn't activated his account yet.
I could override the login method of the AuthenticatesUser trait, but it seems overkill to duplicate all the logic just to change that.
Can I extend the sendFailedLoginResponse method to make some sort of validation there, based on the previous Auth::guard->attempt() call? I mean, does that method leave any information behind that allows me to know, after the call has been made, what made the attempt return false?
Or how would I approach this, without having to override a method completely just to make a simple validation?
Thank you.
public function authenticated(Request $request, User $user ) {
// The user was authenticated check if it the active column is true or not
if($user->active == false){
//Store some flash message here saying he's not account is not active
//Log him out after.
Auth::logout();
}
return redirect()->intended( $this->redirectPath() );
}

Laravel 5.2 : Login "attempt" Event Handling

In Laravel 5.2, i need to do something while the authentication process is being triggered. (Not "after" the login.)
Here are what i have done.
In EventServiceProvider.php:
protected $listen = [
'Illuminate\Auth\Events\Attempting' => ['App\Listeners\UserLoginAttempt#handle'],
];
In app/Listeners/UserLoginAttempt.php:
<?php
namespace App\Listeners;
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Login;
use Carbon\Carbon;
use Auth;
class UserLoginAttempt
{
public function __construct()
{
}
public function handle($event)
{
dd(Auth::user());
exit;
}
}
This always returns null.
** In fact, i have one "custom" field in the Login form, of which i need to capture from the above Event Handler. (I need to check something before actual Login event is done.)
How do i capture the Auth::user() from this (Illuminate\Auth\Events\Attempting) Handler please?
(In other words) How do i talk with the Login Form from the (Illuminate\Auth\Events\Attempting) Handler?
OR ----- Is the Auth::user() object created ONLY AFTER the login is fully processed? Which means i can not get it while in "attempting" stage?
Because i need to capture the login elements first, and if it is something "unauthorized" (after some calculations done in Handler), then i need to terminate the login attempt and route back to the login form from here.. by carrying the Failing Message along.
Please let me know what i'm missing here. Thank you.
According to documentation you are right that Auth::user() object is only created when user is authenticated.
Inside the Illuminate\Auth\Events\Attempting listener;
you can capture the form field by
public function handle(Attempting $event)
{
//return dd($event); // will echo all fields
$event->credentials['email']; // capturing the email field
}
you can also use the User model and then access the user table in DB, to get / check a user field in DB...

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.

How to write a functional test with user authentication?

I am writing a functional test for a page that requires user authentication. I am using the sfDoctrineGuard plugin.
How do I authenticate a user in my test?
Do I have to enter every test through the sign in screen?
Here is my incorrect code:
$b->post('/sfGuardAuth/signin',
array('signin[password]' => 'password',
'signin[username]' => 'user',
'signin[_csrf_token]' => '7bd809388ed8bf763fc5fccc255d042e'))->
with('response')->begin()->
checkElement('h2', 'Welcome Humans')->
end()
Thank you
The tricky part about doing a signin is that the test browser wipes out the context object before each request (see sfBrowser::call()).
You can authenticate the user by injecting a listener which will call the user's signIn() method when the context.load_factories event fires during context initialization:
function signin( sfEvent $event )
{
/* #var $user sfGuardSecurityUser */
if( ! $user = $event->getSubject()->getUser() )
{
throw new RuntimeException('User object not created.');
}
if( ! $user instanceof sfGuardSecurityUser )
{
throw new LogicException(sprintf(
'Cannot log in %s; sfGuardSecurityUser expected.',
get_class($user)
));
}
if( $user->isAuthenticated() )
{
$user->signOut();
}
/* Magic happens here: */
$user->signIn($desired_user_to_log_in_as);
$event->getSubject()->getEventDispatcher()->notify(new sfEvent(
$this,
'application.log',
array(sprintf('User is logged in as "%s".', $user->getUsername()))
));
}
/* Set signin() to fire when the browser inits the context for subsequent
* requests.
*/
$b->addListener('context.load_factories', 'signin');
This will cause the browser to sign in the user for all subsequent requests. Note that sfBrowser does not have a removeListener() method.
Adapted from sfJwtPhpUnitPlugin (FD: I'm the lead dev for this project).
Yes, you do have to sign in to carry out tests. Fortunately, this is much simpler than the method you illustrate above. See the "better and simpler way" on this blog post.
You could make the signin method part of any TestFunctional class according to how you've structured your tests.