Closed amenk closed 1 year ago
@amenk For Contao 5 the login procedure has changed/simplified.
<?php
declare(strict_types=1);
namespace Markocupic\ContaoProgrammaticallyLoginBundle\Controller;
use Contao\BackendUser;
use Contao\Controller;
use Contao\CoreBundle\ContaoCoreBundle;
use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\FrontendUser;
use Contao\Message;
use Contao\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/login_test/frontend', name: 'login_test_frontend', defaults: ['_scope' => 'frontend', '_token_check' => false])]
#[Route('/login_test/backend', name: 'login_test_backend', defaults: ['_scope' => 'backend', '_token_check' => false])]
class LoginTestController extends AbstractController
{
private const AUTHENTICATOR_BACKEND = 'contao.security.login_authenticator.contao_backend';
private const AUTHENTICATOR_FRONTEND = 'contao.security.login_authenticator.contao_frontend';
public function __construct(
private readonly ContaoFramework $framework,
private readonly Security $security,
private readonly RequestStack $requestStack,
) {
}
public function __invoke(): Response
{
$this->framework->initialize();
$request = $this->requestStack->getCurrentRequest();
$scope = $this->getContaoScope($request);
$identifier = $this->getIdentifierFromOauth();
$user = $this->loadContaoUser($identifier, $scope);
if (!$user) {
// Create user if not exists
//$this->createUser($identifier, $scope);
// Or stop login process and redirect to error page
Message::addInfo("User with username '$identifier' not found.");
// Redirect to error page
Controller::redirect('...');
}
// Do more checks
// $this->isDisabledUser();
// $this->logSomething();
// $this->dispatchEvent();
// etc.
// Login the Contao user using Security::login() (introduced in symfony/security-bundle version 6.3)
// https://symfony.com/blog/new-in-symfony-6-3-login-and-logout-improvements
// https://symfony.com/doc/current/security.html#login-programmatically
if ('backend' === $scope) {
// $targetPath = $this->getTargetPathFromSession();
$targetPath = '/contao';
$request->request->set('_target_path', base64_encode($targetPath));
$request->request->set('_always_use_target_path', '1');
return $this->security->login($user, self::AUTHENTICATOR_BACKEND);
// or use a custom redirection logic (e.g. redirect users to their account page)
// return new RedirectResponse('...');
}
// If scope is "frontend"
// $targetPath = $this->getTargetPathFromSession();
$targetPath = 'https://www.test.com';
$request->request->set('_target_path', base64_encode($targetPath));
$request->request->set('_always_use_target_path', '1');
return $this->security->login($user, self::AUTHENTICATOR_FRONTEND);
// or use a custom redirection logic (e.g. redirect users to their account page)
// return new RedirectResponse('...');
}
protected function getContaoScope(Request $request): string
{
return $request->attributes->get('_scope');
}
protected function getIdentifierFromOauth(): string
{
// Retrieve username from oauth2 token
// ...
// ...
return 'testuser';
}
protected function loadContaoUser(string $identifier, string $contaoScope): User|null
{
if (ContaoCoreBundle::SCOPE_BACKEND === $contaoScope) {
return BackendUser::loadUserByIdentifier($identifier);
}
if (ContaoCoreBundle::SCOPE_FRONTEND === $contaoScope) {
return FrontendUser::loadUserByIdentifier($identifier);
}
throw new \LogicException("Invalid Contao scope! Scope must be 'backend' or 'frontend', '$contaoScope' provided.");
}
}
thanks for the info. As you pinned 8.2 now this can be closed :-)
There seems to be a mismatch between the
composer.json
declaration ^8.1 and the use of a readonly class:Context: We are currently just considering this module as a base for a Shibboleth Auth Plugin for Contao 4.13