Otomatik kayıt sonrası kullanıcı kimlik doğrulaması


114

Symfony 2'de sıfırdan bir iş uygulaması oluşturuyoruz ve kullanıcı kaydı akışında biraz engelle karşılaştım: kullanıcı bir hesap oluşturduktan sonra, bunun yerine bu kimlik bilgileriyle otomatik olarak oturum açmalıdır derhal kimlik bilgilerini tekrar sağlamaya zorlanma.

Bu konuda deneyimi olan veya beni doğru yöne yönlendirebilen var mı?

Yanıtlar:


146

Symfony 4.0

Bu süreç symfony 3'ten 4'e değişmedi, ancak burada yeni önerilen AbstractController'ın kullanıldığı bir örnek var. Hem hizmetler security.token_storagehem de sessionhizmetler ana getSubscribedServicesyönteme kaydedilir, böylece bunları denetleyicinize eklemeniz gerekmez.

use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use YourNameSpace\UserBundle\Entity\User;

class LoginController extends AbstractController{

    public function registerAction()
    {    
        $user = //Handle getting or creating the user entity likely with a posted form
        $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
        $this->container->get('security.token_storage')->setToken($token);
        $this->container->get('session')->set('_security_main', serialize($token));
        // The user is now logged in, you can redirect or do whatever.
    }

}

Symfony 2.6.x - Symfony 3.0.x

Symfony 2.6'dan itibaren security.context, lehine kullanımdan kaldırılmıştır security.token_storage. Denetleyici artık basitçe:

use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use YourNameSpace\UserBundle\Entity\User;

class LoginController extends Controller{

    public function registerAction()
    {    
        $user = //Handle getting or creating the user entity likely with a posted form
        $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
        $this->get('security.token_storage')->setToken($token);
        $this->get('session')->set('_security_main', serialize($token));
    }

}

Bu kullanımdan kaldırılmış olsa security.contextda, geriye dönük uyumlu olacak şekilde yapıldığı için kullanmaya devam edebilirsiniz . Symfony 3 için güncellemeye hazır olun

Güvenlik için 2.6 değişiklikleri hakkında daha fazla bilgiyi buradan okuyabilirsiniz: https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md

Symfony 2.3.x

Bunu symfony 2.3'te başarmak için artık belirteci güvenlik bağlamında ayarlayamazsınız. Ayrıca jetonu oturuma kaydetmeniz gerekir.

Aşağıdaki gibi bir güvenlik duvarına sahip bir güvenlik dosyası varsayarsak:

// app/config/security.yml
security:
    firewalls:
        main:
            //firewall settings here

Ve benzer bir denetleyici eylemi:

use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use YourNameSpace\UserBundle\Entity\User;

class LoginController extends Controller{

    public function registerAction()
    {    
        $user = //Handle getting or creating the user entity likely with a posted form
        $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
        $this->get('security.context')->setToken($token);
        $this->get('session')->set('_security_main',serialize($token));
        //Now you can redirect where ever you need and the user will be logged in
    }

}

Belirteç oluşturmak için bir UsernamePasswordToken, Bu 4 parametreyi kabul eder: Kullanıcı Varlığı, Kullanıcı Kimlik Bilgileri, Güvenlik Duvarı Adı, Kullanıcı Rolleri. Jetonun geçerli olması için kullanıcı kimlik bilgilerini sağlamanıza gerek yoktur.

security.contextHemen yeniden yönlendirecekseniz belirteci üzerinde ayarlamanın gerekli olduğundan% 100 emin değilim . Ama incitmiş gibi görünmüyor, bu yüzden onu bıraktım.

Sonra önemli kısım, oturum değişkeninin ayarlanması. Değişkenler adlandırma kuralı olan _security_bu durumda, güvenlik duvarı adından mainverme_security_main


1
Kodu uyguladım, Kullanıcı başarıyla günlüğe girdi, ancak $ this-> getUser () nesnesi NULL döndürüyor. Herhangi bir fikir?
sathish

2
Olmadan çılgın şeyler oluyordu $this->get('session')->set('_security_main', serialize($token));. Teşekkürler @Chausser!
Dmitriy

1
Adlı bir güvenlik duvarı için belirteç ayarlarsanız Symfony 2.6 ile mainVE adlandırılmış başka güvenlik duvarı ile doğrulanır admin(kullanıcıyı taklit gibi), garip bir şey olur: _security_adminalır UsernamePasswordTokenSağladığınız kullanıcı ile, yani gelen "bağlantısız" olsun senin adminduvarı. "Yönetici" güvenlik duvarı belirtecinin nasıl korunacağı hakkında bir fikriniz var mı?
gremo

1
Dürüst olmak gerekirse, aynı anda 2 güvenlik duvarı için kimliğinizin doğrulanabileceğinden emin değilim, iyice araştırın, ancak bu arada ayrı bir soru sormalısınız
Chase,

3
@Chausser çalışmasını sağlamayı başardı. Cevabınız tamamen doğrudur (ve güncellenmiştir), yalnızca aynı hedef güvenlik duvarısetToken(..) altında aradığınızda veya henüz kimliği doğrulanmadan aradığınızda işe yarayan tek şey .
gremo

65

Sonunda bunu çözdüm.

Kullanıcı kaydının ardından, sağlayıcı yapılandırmanızda kullanıcı varlığınız olarak ayarladığınız her şeyin bir nesne örneğine erişiminiz olmalıdır. Çözüm, bu kullanıcı varlığıyla yeni bir simge oluşturmak ve bunu güvenlik bağlamına aktarmaktır. Kurulumuma dayalı bir örnek:

RegistrationController.php:

$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER'));
$this->get('security.context')->setToken($token);

mainUygulamanız için güvenlik duvarının adı nerede (teşekkürler, @Joe). Gerçekten de hepsi bu; sistem artık kullanıcınızı yeni oluşturdukları kullanıcı olarak tamamen oturum açmış olarak kabul eder.

DÜZENLEME: @ Miquel'in yorumuna göre, denetleyici kodu örneğini yeni bir kullanıcı için makul bir varsayılan rol içerecek şekilde güncelledim (ancak bu, uygulamanızın özel ihtiyaçlarına göre ayarlanabilir).


2
Symfony 2'nin yayın sürümünde bu pek doğru değil. Kullanıcının rollerini, UsernamePasswordToken kurucusuna dördüncü argüman olarak iletmeniz gerekir, aksi takdirde kimlik doğrulaması yapılmamış olarak işaretlenir ve kullanıcının hiçbir rolü olmayacaktır.
Michael

Peki ya "Beni hatırla" bayrağı? Kullanıcılara elle nasıl giriş yapılır, ancak aynı zamanda sonsuza kadar oturum açmaları gerekir. Bu kod parçası bu sorunu çözmez.
maectpo

@maectpo bu benim orijinal gereksinimlerimin kapsamında değildi, ancak kulağa harika bir takip yanıtı gibi geliyor. Ne bulduğunuzu bize bildirin.
Sorunlu

Bir sorunum var Bu şekilde giriş yapabilirim, ancak app.user değişkeni boş. Bu giriş sürecinde bu değişkeni doldurmanın herhangi bir yolunu biliyor musunuz? - Kullanıcıyı (dizeyi) ve parolayı (dizeyi) Referans olarak gönderiyorum
unairoldan

1
Marc'ın aşağıda söylediği gibi, UsernamePasswordToken ad alanını kaydetmeniz gerekiyor:use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
MrGlass

6

Bir UserInterface nesneniz varsa (ve çoğu zaman durum böyle olmalıdır), son bağımsız değişken için uyguladığı getRoles işlevini kullanmak isteyebilirsiniz. Dolayısıyla, logUser işlevini oluşturursanız, şöyle görünmelidir:

public function logUser(UserInterface $user) {
    $token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
    $this->container->get('security.context')->setToken($token);
}

6

Symfony 2.2 kullanıyorum ve benim deneyimim Problematic'inkinden biraz farklıydı , bu yüzden bu, bu sorudaki tüm bilgilerin ve kendime ait bazı bilgilerin birleşik bir versiyonu.

Üçüncü parametrenin kurucu için değeri konusunda Joe'nun yanlış olduğunu düşünüyorum . Bir kimlik doğrulama (kullanıcı değil) sağlayıcısının anahtarı olması gerekiyordu. Kimlik doğrulama sistemi tarafından, farklı sağlayıcılar için oluşturulan belirteçleri ayırt etmek için kullanılır. Aşağıdan inen herhangi bir sağlayıcı , yalnızca sağlayıcı anahtarı kendisiyle eşleşen belirteçleri doğrulayacaktır. Örneğin, oluşturduğu jetonun anahtarını karşılık gelen anahtarla eşleşecek şekilde ayarlar . Bu, tek bir güvenlik duvarının birden çok kullanıcı adı + şifre sağlayıcısına sahip olmalarına ve birbirlerinin üzerine basmalarına izin verir. Bu nedenle, diğer sağlayıcılarla çakışmayacak bir anahtar seçmemiz gerekiyor. Ben kullanıyorum .$providerKeyUsernamePasswordTokenUserAuthenticationProviderUsernamePasswordFormAuthenticationListenerDaoAuthenticationProvider'new_user'

Uygulamamın diğer bölümlerinde, kimlik doğrulama başarılı olayına bağlı birkaç sistemim var ve bu yalnızca simgeyi bağlama göre ayarlayarak tetiklenmiyor. EventDispatcherKonteynırdan almam ve olayı manuel olarak ateşlemem gerekiyordu. Açık bir oturum açma isteğine yanıt olarak değil, kullanıcının kimliğini örtük olarak doğruladığımız için etkileşimli bir oturum açma etkinliğini de tetiklememeye karar verdim .

use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;

$user = // get a Symfony user instance somehow
$token = new UsernamePasswordToken(
        $user, null, 'new_user', $user->getRoles() );
$this->get( 'security.context' )->setToken( $token );
$this->get( 'event_dispatcher' )->dispatch(
        AuthenticationEvents::AUTHENTICATION_SUCCESS,
        new AuthenticationEvent( $token ) );

Kullanımının $this->get( .. ), parçacığın bir denetleyici yönteminde olduğunu varsaydığını unutmayın . Kodu başka bir yerde kullanıyorsanız ContainerInterface::get( ... ), çevreye uygun bir şekilde aramak için bunları değiştirmeniz gerekecektir . Olduğu gibi, kullanıcı varlıklarım uyguluyor, UserInterfaceböylece onları doğrudan jetonla kullanabiliyorum. Sizinki yoksa, onları UserInterfaceörneklere dönüştürmenin bir yolunu bulmanız gerekecek .

Bu kod işe yarıyor, ancak bununla çalışmak yerine Symfony'nin kimlik doğrulama mimarisini hackliyor gibi hissediyorum. Yeni bir kimlik doğrulama sağlayıcısını kendi simge sınıfıyla uygulamak, .NET Framework'ü ele geçirmek yerine muhtemelen daha doğru olacaktır UsernamePasswordToken. Ayrıca, uygun bir sağlayıcı kullanmak, olayların sizin için ele alındığı anlamına gelir.


4

Buraya geri dönmemi sağlayan aynı takip sorusu olan birinin olması durumunda:

çağrı

$this->container->get('security.context')->setToken($token); 

yalnızca security.contextkullanılan rota için akımı etkiler .

Yani, yalnızca güvenlik duvarının denetimi içindeki bir url'den bir kullanıcı oturum açabilirsiniz.

(Gerekirse rota için bir istisna ekleyin - IS_AUTHENTICATED_ANONYMOUSLY)


1
Bunu bir seans için nasıl yaptığını biliyor musun? Sadece mevcut istek yerine mi?
Jake N

3

Symfony 4.4 ile, denetleyici yönteminizde aşağıdakileri kolayca yapabilirsiniz (Symfony belgelerine bakın: https://symfony.com/doc/current/security/guard_authentication.html#manually-authenticating-a-user ):

// src/Controller/RegistrationController.php
// ...

use App\Security\LoginFormAuthenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;

class RegistrationController extends AbstractController
{
    public function register(LoginFormAuthenticator $authenticator, GuardAuthenticatorHandler $guardHandler, Request $request)
    {
        // ...

        // after validating the user and saving them to the database
        // authenticate the user and use onAuthenticationSuccess on the authenticator
        return $guardHandler->authenticateUserAndHandleSuccess(
            $user,          // the User object you just created
            $request,
            $authenticator, // authenticator whose onAuthenticationSuccess you want to use
            'main'          // the name of your firewall in security.yaml
        );
    }
}

Önemli bir şey, güvenlik duvarınızın ayarlanmadığından emin olun lazy. Eğer öyleyse, jeton hiçbir zaman oturumda depolanmaz ve asla oturum açamazsınız.

firewalls:
    main:
        anonymous: ~ # this and not 'lazy'

2

Burada daha önce de belirtildiği gibi, bu zor olan $ providerKey parametresi gerçekte güvenlik duvarı kuralınızın adından başka bir şey değildir, aşağıdaki örnekte 'foobar'.

firewalls:
    foobar:
        pattern:    /foo/

Örneğin, herhangi bir dizeyi, örneğin blablabla, UsernamePasswordToken'a üçüncü parametre olarak iletirsem, bunun da işe yarayacağını bana açıklayabilir misiniz ? bu parametre ne anlama geliyor?
Mikhail

1
Bu parametre, belirtecinizi belirli bir güvenlik duvarı sağlayıcısına bağlar. Çoğu durumda yalnızca bir sağlayıcınız olacaktır, bu yüzden bu konuda endişelenmeyin.
Gottlieb Notschnabel

2

Buradaki tüm cevapları denedim ve hiçbiri işe yaramadı. Bir denetleyicideki kullanıcılarımın kimliğini doğrulayabilmemin tek yolu, bir alt istekte bulunup yeniden yönlendirmektir. İşte benim kodum, silex kullanıyorum ama onu kolayca symfony2'ye uyarlayabilirsiniz:

$subRequest = Request::create($app['url_generator']->generate('login_check'), 'POST', array('_username' => $email, '_password' => $password, $request->cookies->all(), array(), $request->server->all());

$response = $app->handle($subRequest, HttpKernelInterface::MASTER_REQUEST, false);

return $app->redirect($app['url_generator']->generate('curriculos.editar'));

1

Symfony 2.8.11 sürümünde (muhtemelen daha eski ve daha yeni sürümler için çalışmaktadır), FOSUserBundle kullanıyorsanız bunu yapmanız yeterlidir:

try {
    $this->container->get('fos_user.security.login_manager')->loginUser(
    $this->container->getParameter('fos_user.firewall_name'), $user, null);
} catch (AccountStatusException $ex) {
    // We simply do not authenticate users which do not pass the user
    // checker (not enabled, expired, etc.).
}

Diğer çözümlerde gördüğüm gibi olay göndermeye gerek yok.

FOS \ UserBundle \ Controller \ RegistrationController :: AuthenticateUser'dan temin edildi

(composer.json FOSUserBundle sürümünden: "friendsofsymfony / user-bundle": "~ 1.3")

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.