Is There Any Sort of "Pre Login" Event or Similar

Is there any sort of pre login event or similar?

So, there's no 'official' pre-login event. But thankfully it's not hard to set one up since Symfony2 is so extendable. The trick is to use your own service to handle authentication.

Symfony uses this class when using a login form:

Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener

If you override the security.authentication.listener.form.class parameter (originally defined in Symfony\Bundle\SecurityBundle\Resources\config\security_listeners.xml) you can use a custom listener that extends UsernamePasswordFormAuthenticationListener.

All that's left to do is override the attemptAuthentication() method to dispatch the custom event.

(Actually you also need to store the event dispatcher as a class property in __construct())

This method should work with other authentication methods - all you'd need to do is modify the appropriate listener (ie BasicAuthenticationListener, X509AuthenticationListener, etc.)

Symfony - Pre login event listener

Generally all login stuff in symfony is executed by a listener to the kernel.request event, mostly within the Firewall listener of the Symfony security component. I did not use the HWIOAuthBundle bundle yet, but it seems it also just uses the Symfony Security component.

If you just want to execute certain actions before the login/authentication happens, you only need to register an event listener to the kernel.request with a higher priority than the Firewall listener.

You can do that as described in the Symfony docs (Events and Event Listeners). First create your Event listener class in src/AppBundle/EventListener/YourListener.php:

namespace AppBundle\EventListener;

use Symfony\Component\HttpKernel\Event\GetResponseEvent;

class YourListener
{
public function onKernelRequest(GetResponseEvent $event)
{
// do stuff
}
}

Then register your service in your app/config/services.yml file:

services:
AppBundle\EventListener\YourListener:
tags:
- { name: kernel.event_listener, event: kernel.request, priority: 9 }

According to this page the Firewall has a priority of 8. So the priority of your event listener should be higher than that to be executed before the login happens (I used 9 in the example above).

FOSUserBundle - perform function upon initial login

I just had a look at this and it seems you can use an eventSubscriber to subscribe to the SecurityEvents::INTERACTIVE_LOGIN event to get where you need to be.

class RegistrationSubscriber implements EventSubscriberInterface
{
private $tokenStorage;

public function __construct(TokenStorage $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public static function getSubscribedEvents()
{
return [
SecurityEvents::INTERACTIVE_LOGIN => [
['lastLogin', 150],
],
];
}
public function lastLogin(InteractiveLoginEvent $event){
$user = $this->tokenStorage->getToken()->getUser();
if($user->getLastLogin() == null){
//Do something
}
}

In my testing on the first login $user->getLastLogin() is null so you can put any logic you need here.

How to make some security checks before the user will be granted to log-in (pre-login)?

To perform some pre/post-login checks (that means before/after the user authentication) one of the most simple and flexible solutions, offered by the Symfony framework, is to learn How to Create and Enable Custom User Checkers.

If you need more control and flexibility the best option is to learn How to Create a Custom Authentication System with Guard.
Take a look at the simple implementation example below:

security.yml

    firewall_name:
guard:
authenticators:
- service_name_for_guard_authenticator
entry_point: service_name_for_guard_authenticator <-- important to add a default one (as described in the docs) if you have many custom authenticators (facebook...)

service.xml

<service id="service_name_for_guard_authenticator"
class="AppBundle\ExampleFolderName\YourGuardAuthClassName">
<argument type="service" id="router"/>
<argument type="service" id="security.password_encoder"/>
</service>

YourGuardAuthClassName.php

use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder;

class YourGuardAuthClassName extends AbstractGuardAuthenticator
{
private $router;
private $passwordEncoder;

public function __construct(
Router $router,
UserPasswordEncoder $passwordEncoder)
{
$this->router = $router;
$this->passwordEncoder = $passwordEncoder;
}

public function start(Request $request, AuthenticationException $authException = null)
{
$response = new RedirectResponse($this->router->generate('your_user_login_route_name'));

return $response;
}

public function getCredentials(Request $request)
{
# CHECK IF IT'S THE CHECK LOGIN ROUTE
if ($request->attributes->get('_route') !== 'your_user_login_route_name'
|| !$request->isMethod('POST')) {
return null;
}
# GRAB ALL REQUEST PARAMETERS
$params = $request->request->all();
# SET LOGIN CREDENTIALS
return array(
'email' => $params['email'],
'password' => $params['password'],
);
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
$email = $credentials['email'];
$user = $userProvider->loadUserByUsername($email);
if (! $user){
throw new UsernameNotFoundException();
}

return $user;
}

public function checkCredentials($credentials, UserInterface $user)
{
# YOU CAN ADD YOUR CHECKS HERE!
if (! $this->passwordEncoder->isPasswordValid($user, $credentials['password'])) {
throw new BadCredentialsException();
}
return true;
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
# OYU CAN ALSO USE THE EXCEPTIONS TO ADD A FLASH MESSAGE (YOU HAVE TO INJECT YOUR OWN FLASH MESSAGE SERVICE!)
if ($exception instanceof UsernameNotFoundException){
$this->flashMessage->error('user.login.exception.credentials_invalid');
}
if ($exception instanceof BadCredentialsException){
$this->flashMessage->error('user.login.exception.credentials_invalid');
}

return new RedirectResponse($this->router->generate('your_user_login_route_name'));
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return new RedirectResponse($this->router->generate('your_success_login_route_name'));
}

public function supportsRememberMe()
{
return false;
}
}

Mixpanel - Linking pre login and post login events to user on android

As per MixPanel guidance events can be linked if alias is set first and then identifier.

//set alias when user signs up

MixpanelAPI mixpanelAPI = MixpanelAPI.getInstance(context, MixPanelConstants.MIX_PANEL_TOKEN);
mixpanelAPI.alias("myAlias", mixpanelAPI.getDistinctId());

//set identifier when user logs in
mixpanelAPI.identify("user.alias");

Alias is set when user performs registration, right? Mixpanel recommends to set Alias once during the life time of the user. However this guidance doesn't support linking of pre-login and post-login events if user doesn't perform registration and logins directly (Existing user scenario)



Related Topics



Leave a reply



Submit