답변:
심포니 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.
}
}
Symfony 2.6.x-Symfony 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
이전 버전과 호환되도록 만들어 졌으므로 계속 사용할 수 있습니다 . Symfony 3 용으로 업데이트 할 준비 만하십시오.
보안을위한 2.6 변경 사항에 대한 자세한 내용은 https://github.com/symfony/symfony/blob/2.6/UPGRADE-2.6.md에서 확인할 수 있습니다.
심포니 2.3.x
Symfony 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 가지 매개 변수를 허용합니다. 토큰이 유효하기 위해 사용자 자격 증명을 제공 할 필요가 없습니다.
security.context
즉시 리디렉션하려는 경우 토큰 설정 이 필요하다고 100 % 확신하지 않습니다 . 하지만 아프지 않은 것 같아서 떠났습니다.
그런 다음 중요한 부분은 세션 변수를 설정하는 것입니다. 변수 이름 지정 규칙 _security_
뒤에 방화벽 이름 main
이옵니다._security_main
$this->get('session')->set('_security_main', serialize($token));
. 감사합니다, @Chausser!
main
다른 방화벽 admin
(사용자를 가장하는 것처럼)으로 인증을 _security_admin
받으면 이상한 일이 발생합니다. UsernamePasswordToken
즉, 제공 한 사용자와 함께 가져옵니다 . 즉, "연결 해제"됩니다. 당신의 admin
방화벽. "관리자"방화벽에 대한 토큰을 유지하는 방법을 아십니까?
setToken(..)
에서 호출 하거나 아직 인증 되지 않은 경우에만 작동합니다 .
마침내 이것을 알아 냈습니다.
사용자 등록 후 공급자 구성에서 사용자 엔터티로 설정 한 개체 인스턴스에 액세스 할 수 있어야합니다. 해결책은 해당 사용자 엔터티로 새 토큰을 만들고이를 보안 컨텍스트에 전달하는 것입니다. 내 설정을 기반으로 한 예는 다음과 같습니다.
RegistrationController.php:
$token = new UsernamePasswordToken($userEntity, null, 'main', array('ROLE_USER'));
$this->get('security.context')->setToken($token);
main
응용 프로그램의 방화벽 이름은 어디에 있습니까 (@Joe에게 감사드립니다). 그게 전부입니다. 이제 시스템은 사용자가 방금 생성 한 사용자로 완전히 로그인 한 것으로 간주합니다.
편집 : @Miquel의 의견에 따라 새 사용자를위한 합리적인 기본 역할을 포함하도록 컨트롤러 코드 샘플을 업데이트했습니다 (당연히 애플리케이션의 특정 요구에 따라 조정할 수 있음).
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
UserInterface 객체가있는 경우 (대부분의 경우) 마지막 인수에 대해 구현하는 getRoles 함수를 사용할 수 있습니다. 따라서 logUser 함수를 생성하면 다음과 같아야합니다.
public function logUser(UserInterface $user) {
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->container->get('security.context')->setToken($token);
}
저는 Symfony 2.2를 사용하고 있으며 내 경험은 Problematic의 경험과 약간 달랐습니다. 때문에이 질문의 모든 정보와 내 자신의 정보를 결합한 버전입니다.
생성자 의 세 번째 매개 변수 인의 값에 대해 Joe 가 틀렸다고 생각 $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
인스턴스 합니다.
이 코드는 작동하지만 Symfony의 인증 아키텍처를 사용하는 것보다 해킹하는 것 같습니다. .NET Framework를 하이재킹하는 것보다 자체 토큰 클래스 로 새 인증 공급자 를 구현하는 것이 더 정확할 것입니다 UsernamePasswordToken
. 또한 적절한 공급자를 사용하면 이벤트가 처리되었음을 의미합니다.
Symfony 4.4를 사용하면 컨트롤러 메소드에서 다음을 수행 할 수 있습니다 (Symfony 문서에서 참조 : 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
);
}
}
한 가지 중요한 것은 방화벽이로 설정되어 있지 않은지 확인하는 것 lazy
입니다. 그렇다면 토큰은 세션에 저장되지 않으며 로그인되지도 않습니다.
firewalls:
main:
anonymous: ~ # this and not 'lazy'
여기에서 이미 언급했듯이이 애매한 $ providerKey 매개 변수는 실제로 방화벽 규칙의 이름 인 'foobar'(아래 예의 경우)에 지나지 않습니다.
firewalls:
foobar:
pattern: /foo/
blablabla
UsernamePasswordToken에 세 번째 매개 변수로 문자열을 전달하면 왜 작동하는지 설명해 주 시겠습니까? 이 매개 변수는 무엇을 의미합니까?
나는 여기에서 모든 대답을 시도했지만 아무것도 작동하지 않았습니다. 컨트롤러에서 사용자를 인증 할 수있는 유일한 방법은 하위 요청을 만든 다음 리디렉션하는 것입니다. 다음은 내 코드입니다. 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'));
Symfony 버전 2.8.11 (아마도 이전 버전과 최신 버전에서 작동)에서 FOSUserBundle을 사용하는 경우 다음을 수행하십시오.
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 \ Controller \ RegistrationController :: authenticateUser에서 영감을 얻었습니다.
(composer.json FOSUserBundle 버전에서 : "friendsofsymfony / user-bundle": "~ 1.3")