स्वचालित पोस्ट-पंजीकरण उपयोगकर्ता प्रमाणीकरण


114

हम सिम्फनी 2 में जमीन से एक व्यावसायिक ऐप बना रहे हैं, और मैंने उपयोगकर्ता पंजीकरण प्रवाह के साथ एक रोड़ा में भाग लिया है: उपयोगकर्ता द्वारा खाता बनाने के बाद, उन्हें स्वचालित रूप से उन क्रेडेंशियल्स के साथ लॉग इन किया जाना चाहिए तुरंत फिर से अपनी साख प्रदान करने के लिए मजबूर किया जा रहा है।

किसी को भी इसके साथ कोई अनुभव था, या मुझे सही दिशा में इंगित करने में सक्षम था?

जवाबों:


146

सिम्फनी 4.0

यह प्रक्रिया 3 से 4 के सिम्फनी से परिवर्तित नहीं हुई है, लेकिन यहां नए अनुशंसित AbstractController का उपयोग करके एक उदाहरण दिया गया है। दोनों सेवाओं security.token_storageऔर sessionसेवाओं को मूल getSubscribedServicesविधि में पंजीकृत किया गया है ताकि आपको अपने नियंत्रक में शामिल न करना पड़े।

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.
    }

}

सिम्फनी 2.6.x - सिम्फनी 3.0.x

सिम्फनी के रूप में 2.6 के security.contextपक्ष में पदावनत किया जाता है security.token_storage। नियंत्रक अब बस हो सकता है:

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));
    }

}

जबकि यह पदावनत है आप अभी भी उपयोग कर सकते हैं security.contextक्योंकि इसे पिछड़े संगत बनाया गया है। बस इसे सिम्फनी 3 के लिए अपडेट करने के लिए तैयार रहें

आप यहां सुरक्षा के लिए 2.6 बदलावों के बारे में अधिक पढ़ सकते हैं: https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md

सिम्फनी 2.3.x

इसे सिम्फनी 2.3 में पूरा करने के लिए आप अब केवल सुरक्षा संदर्भ में टोकन सेट नहीं कर सकते। आपको सत्र में टोकन को बचाने की भी आवश्यकता है।

एक फ़ायरवॉल के साथ एक सुरक्षा फ़ाइल मानकर:

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

और एक नियंत्रक क्रिया भी समान है:

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
    }

}

टोकन निर्माण के लिए आप एक बनाना चाहेंगे UsernamePasswordToken, यह 4 मापदंडों को स्वीकार करता है: उपयोगकर्ता इकाई, उपयोगकर्ता क्रेडेंशियल्स, फ़ायरवॉल नाम, उपयोगकर्ता भूमिकाएं। टोकन के मान्य होने के लिए आपको उपयोगकर्ता क्रेडेंशियल्स प्रदान करने की आवश्यकता नहीं है।

Im 100% निश्चित नहीं security.contextहै कि यदि आप अभी तुरंत पुनर्निर्देशित करने जा रहे हैं तो टोकन सेट करना आवश्यक है। लेकिन यह चोट नहीं लगती है इसलिए मैंने इसे छोड़ दिया है।

फिर महत्वपूर्ण हिस्सा, सत्र चर की स्थापना। _security_इस केस mainमेकिंग में आपके फायरवॉल नाम के बाद वैरिएबल नामकरण कन्वेंशन है_security_main


1
मैंने कोड लागू कर दिया है, उपयोगकर्ता सफलतापूर्वक लॉग इन किया है, लेकिन $ यह-> getUser () ऑब्जेक्ट रिटर्न NULL। कोई उपाय?
सतीश

2
पागल चीजें बिना हो रही थीं $this->get('session')->set('_security_main', serialize($token));। धन्यवाद, @Chausser!
दिमित्री

1
सिम्फनी 2.6 के साथ यदि आप नामित फ़ायरवॉल के लिए टोकन सेट करते mainहैं और आप किसी अन्य फ़ायरवॉल नाम से प्रमाणित होते हैं admin(जैसा कि आप उपयोगकर्ता को प्रतिरूपित कर रहे हैं), तो एक अजीब बात होती है: आपके द्वारा प्रदान किए गए उपयोगकर्ता _security_adminके UsernamePasswordTokenसाथ हो जाता है , अर्थात आपको "छूट" मिल जाती है आपका adminफ़ायरवॉल। किसी भी विचार कैसे "व्यवस्थापक" फ़ायरवॉल के लिए टोकन बनाए रखने के लिए?
gremo

1
ईमानदार होने के लिए यकीन नहीं है कि आप एक ही समय में 2 फायरवॉल के लिए प्रमाणित हो सकते हैं, इस पर ध्यान दें, लेकिन इस दौरान आपको एक अलग सवाल पूछना चाहिए
चेस

3
@ कॉज़र इसे काम करने में कामयाब रहे। आप जवाब देते हैं कि यह पूरी तरह से सही है (और इसे अपडेट किया गया है), केवल एक ही चीज़ यह तब काम करती है जब आप setToken(..)एक ही लक्ष्य फ़ायरवॉल के तहत या अभी तक प्रमाणित किए बिना कॉल करते हैं ।
गार्मो

65

अंत में यह पता लगा।

उपयोगकर्ता पंजीकरण के बाद, आपके पास अपने प्रदाता कॉन्फ़िगरेशन में उपयोगकर्ता इकाई के रूप में जो कुछ भी आप सेट करते हैं, उसके पास ऑब्जेक्ट इंस्टॉफ़ का एक्सेस होना चाहिए। समाधान उस उपयोगकर्ता इकाई के साथ एक नया टोकन बनाना है और इसे सुरक्षा संदर्भ में पास करना है। यहाँ मेरे सेटअप के आधार पर एक उदाहरण दिया गया है:

RegistrationController.php:

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

mainआपके एप्लिकेशन के लिए फ़ायरवॉल का नाम कहां है (धन्यवाद, @ जो)। वास्तव में यही सब कुछ है; सिस्टम अब आपके उपयोगकर्ता को पूरी तरह से लॉग इन के रूप में मानता है जिस उपयोगकर्ता को उन्होंने अभी बनाया है।

संपादित करें: @ मिकेल की टिप्पणी के अनुसार, मैंने एक नए उपयोगकर्ता के लिए एक समझदार डिफ़ॉल्ट भूमिका को शामिल करने के लिए नियंत्रक कोड नमूने को अपडेट किया है (हालांकि स्पष्ट रूप से इसे आपके आवेदन की विशिष्ट आवश्यकताओं के अनुसार समायोजित किया जा सकता है)।


2
यह सिम्फनी 2 के रिलीज़ संस्करण के साथ बिल्कुल सही नहीं है। आपको उपयोगकर्ता के उपयोगकर्ता नाम के चौथे तर्क के रूप में UsernamePasswordToken कंस्ट्रक्टर को पास करने की आवश्यकता है, या इसे अनधिकृत के रूप में चिह्नित किया जाएगा और उपयोगकर्ता के पास उनकी कोई भूमिका नहीं होगी।
माइकल

"मुझे याद करो" ध्वज के बारे में क्या? उपयोगकर्ताओं को हाथ से कैसे लॉगिन करें, लेकिन साथ ही उन्हें हमेशा के लिए लॉग इन किया जाना चाहिए। कोड का यह टुकड़ा उस समस्या को हल नहीं करता है।
मईपो

@maectpo जो मेरी मूल आवश्यकताओं के दायरे में नहीं था, लेकिन एक महान अनुवर्ती उत्तर की तरह लगता है। हमें बताएं कि आप किसके साथ आयेंगे।
समस्याग्रस्त

मेरे पास एक मुद्दा है। मैं इस तरह से लॉग इन कर सकता हूं, लेकिन मैं app.user वेरिएबल खाली हूं। क्या आप इस लॉगिन प्रक्रिया में इस चर को आबाद करने का कोई तरीका जानते हैं? - मैं उपयोगकर्ता (स्ट्रिंग) और पासवर्ड (स्ट्रिंग) को संदर्भ के अनुसार कहता हूं: api.symfony.com/2.0/Symfony/Component/Security/Core/…
unairoldan

1
जैसे नीचे मार्क ने कहा, आपको use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
यूजरनेमपासवर्डटॉकन

6

यदि आपके पास एक UserInterface ऑब्जेक्ट है (और यह ज्यादातर समय होना चाहिए) तो आप getRoles फ़ंक्शन का उपयोग करना चाह सकते हैं जो इसे अंतिम तर्क के लिए लागू करता है। इसलिए यदि आप एक फ़ंक्शन लॉगर बनाते हैं, तो यह इस तरह दिखना चाहिए:

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

6

मैं सिम्फनी 2.2 का उपयोग कर रहा हूं और मेरा अनुभव समस्याग्रस्त की तुलना में थोड़ा अलग था , इसलिए यह इस प्रश्न से सभी जानकारी का एक संयुक्त संस्करण है और साथ ही मेरे अपने कुछ।

मुझे लगता है कि जो के मूल्य के बारे में गलत है $providerKey, तीसरा पैरामीटर UsernamePasswordTokenकंस्ट्रक्टर के लिए। यह एक प्रमाणीकरण (उपयोगकर्ता नहीं) प्रदाता की कुंजी माना जाता है। यह प्रमाणीकरण प्रणाली द्वारा विभिन्न प्रदाताओं के लिए बनाए गए टोकन के बीच अंतर करने के लिए उपयोग किया जाता है। जो भी प्रदाता उतरता है, UserAuthenticationProviderवह केवल टोकन को प्रमाणित करेगा, जिसकी प्रदाता कुंजी स्वयं से मेल खाती है। उदाहरण के लिए, UsernamePasswordFormAuthenticationListenerटोकन की कुंजी सेट करता है जो इसके अनुरूप मेल खाता है DaoAuthenticationProvider। एक एकल फ़ायरवॉल के पास कई उपयोगकर्ता नाम + पासवर्ड प्रदाता हैं, उनके बिना एक दूसरे पर कदम नहीं रखते हैं। इसलिए हमें एक ऐसी कुंजी चुनने की आवश्यकता है जो किसी अन्य प्रदाता के साथ संघर्ष न करे। मैं उपयोग करता हूं 'new_user'

मेरे पास मेरे अनुप्रयोग के अन्य भागों में कुछ सिस्टम हैं जो प्रमाणीकरण सफलता की घटना पर निर्भर करते हैं , और यह केवल संदर्भ पर टोकन सेट करने से निकाल नहीं है। मुझे EventDispatcherकंटेनर से प्राप्त करना था और घटना को मैन्युअल रूप से फायर करना था। मैंने एक इंटरेक्टिव लॉगिन इवेंट को फायर करने के खिलाफ भी फैसला किया क्योंकि हम उपयोगकर्ता को स्पष्ट रूप से लॉगिन अनुरोध के जवाब में नहीं, बल्कि स्पष्ट रूप से प्रमाणित कर रहे हैं।

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 ) );

ध्यान दें कि $this->get( .. )स्निपेट का उपयोग नियंत्रक विधि में है। यदि आप कहीं और कोड का उपयोग कर रहे हैं, तो आपको ContainerInterface::get( ... )पर्यावरण के लिए उपयुक्त तरीके से कॉल करने के लिए उन्हें बदलना होगा । जैसा कि यह होता है कि मेरी उपयोगकर्ता इकाइयाँ लागू होती हैं, UserInterfaceइसलिए मैं उन्हें सीधे टोकन के साथ उपयोग कर सकता हूं। यदि आपका नहीं है तो आपको उन्हें UserInterfaceउदाहरणों में बदलने का एक तरीका खोजना होगा ।

यह कोड काम करता है, लेकिन मुझे ऐसा लगता है कि यह इसके साथ काम करने के बजाय सिम्फनी के प्रमाणीकरण वास्तुकला के आसपास हैकिंग कर रहा है। संभवतः अपने ही टोकन वर्ग के साथ एक नए प्रमाणीकरण प्रदाता को अपहृत करने के बजाय इसे लागू करना अधिक सही होगा UsernamePasswordToken। इसके अलावा, एक उचित प्रदाता का उपयोग करने का मतलब होगा कि घटनाएं आपके लिए नियंत्रित की गई थीं।


4

मामले में किसी के पास भी वही अनुवर्ती प्रश्न है जो मुझे यहाँ वापस आने के लिए बनाए रखा है:

कॉलिंग

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

security.contextउपयोग किए गए मार्ग के लिए केवल वर्तमान प्रभाव ।

यानी आप केवल फ़ायरवॉल के नियंत्रण में एक url से किसी उपयोगकर्ता को लॉग इन कर सकते हैं।

(यदि आवश्यक हो तो मार्ग के लिए एक अपवाद जोड़ें - IS_AUTHENTICATED_ANONYMOUSLY)


1
क्या आप जानते हैं कि आप एक सत्र के लिए यह कैसे करते हैं? बल्कि केवल वर्तमान अनुरोध के लिए?
जेक एन

3

सिम्फनी 4.4 के साथ, आप बस अपने कंट्रोलर मेथड में कर सकते हैं (सिम्फनी डॉक्यूमेंटेशन से देखें: https://symfony.com/doc/current/security/guard_authentication.html#manually-authenticant-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
        );
    }
}

एक महत्वपूर्ण बात, सुनिश्चित करें कि आपका फ़ायरवॉल सेट नहीं है lazy। यदि यह है, तो टोकन को सत्र में कभी संग्रहीत नहीं किया जाएगा और आप कभी भी लॉग इन नहीं करेंगे।

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

2

जैसा कि समस्याग्रस्त यहाँ पहले ही उल्लेख किया गया है, यह मायावी $ प्रदाताकेई पैरामीटर वास्तव में आपके फ़ायरवॉल नियम के नाम से अधिक कुछ नहीं है, नीचे दिए गए उदाहरण के मामले में 'फ़ॉबर'।

firewalls:
    foobar:
        pattern:    /foo/

क्या आप मुझे समझा सकते हैं कि अगर मैं उदाहरण के लिए किसी भी स्ट्रिंग blablablaको UsernamePasswordToken के तीसरे पैरामीटर के रूप में पास करता हूं तो यह भी काम करेगा? इस पैरामीटर का क्या मतलब है?
मिखाइल

1
यह पैरामीटर एक विशिष्ट फ़ायरवॉल प्रदाता को आपके टोकन को बांधता है। ज्यादातर मामलों में आपके पास केवल एक प्रदाता होगा, इसलिए इसके बारे में परेशान न हों।
गोटलिब नॉट्चैनाबेल

2

मैंने यहां सभी उत्तरों की कोशिश की और कोई भी काम नहीं किया। जिस तरह से मैं एक नियंत्रक पर अपने उपयोगकर्ताओं को प्रमाणित कर सकता था वह सबरेक्स्ट और फिर रीडायरेक्ट करने से है। यहाँ मेरा कोड है, मैं silex का उपयोग कर रहा हूँ, लेकिन आप इसे आसानी से symfony2 में बदल सकते हैं:

$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

यदि आप FOSUserBundle का उपयोग करते हैं तो सिम्फनी संस्करण 2.8.11 पर (शायद पुराने और नए संस्करणों के लिए काम कर रहा है), बस यह करें:

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.).
}

जैसा कि मैंने अन्य समाधानों में देखा है घटना को फैलाने की कोई आवश्यकता नहीं है।

FOS \ UserBundle \ नियंत्रक \ RegistrationController :: से प्रमाणित है

(कंपोज़र.जसन फ़ॉउसरबंडल संस्करण से: "मित्रोफ़्समीफ़ोनी / यूज़र-बंडल": "~ 1.3")

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.