markocupic / swiss-alpine-club-contao-login-client-bundle

Swiss Alpine Club SSO Login Client for Contao
MIT License
5 stars 3 forks source link

Contao 5 upgrade #5

Closed markocupic closed 6 months ago

markocupic commented 1 year ago
<?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.");
    }
}