如何在授权成功后返回 json 对象而不是重定向


How to return the json object instead of redirection after the successful authorization

如何在成功授权后返回 json 对象而不是重定向到默认路径?我使用的是Symfony 3.0.1,但我不使用FOSBundle。

我的登录控制器如下所示:

class ClientLoginController extends Controller
{
    /**
     * @Route("/login", name="login")
     */
    public function loginAction(Request $request)
    {
        $client = new Client();
        $form   = $this->createForm(ClientLoginType::class, $client);
        $form->handleRequest($request);
        $authenticationUtils = $this->get('security.authentication_utils');
        $lastEmail = $authenticationUtils->getLastUsername();
        $error = $authenticationUtils->getLastAuthenticationError();
        if ($form->isSubmitted() && $form->isValid())
        {
            return new JsonResponse(
                array(
                    'message' => 'Success! You're authorised!',
                    'result'  => $this->renderView('SymfonyBundle::client/success.html.twig')
                ), 200);
        }
        return $this->render(
            'SymfonyBundle::security/security.html.twig',
            array(
                'login_form' => $form->createView(),
                'error'         => $error,
                'last_email' => $lastEmail,
            )
        );
    }
}

security.yml 配置中的登录部分如下所示:

form_login:
    login_path: login
    check_path: login
    username_parameter: _email
    failure_forward: false
    default_target_path: login
    csrf_token_generator: security.csrf.token_manager

提前谢谢你!

当您将登录表单发布到安全配置中设置为check_path的URL时,symfony将拦截侦听器的请求并在内部处理用户身份验证,然后根据配置重定向到页面。因此,if ($form->isSubmitted() && $form->isValid())中的代码实际上永远不会被调用。

您可以通过多种方式覆盖此行为:

  • 创建身份验证侦听器,侦听AuthenticationEvents::AUTHENTICATION_SUCCESSAuthenticationEvents::AUTHENTICATION_FAILURE事件
  • 创建身份验证处理程序
  • 创建自定义身份验证系统

上面针对身份验证处理程序案例的链接博客文章正是您所需要的。我只是在这里复制粘贴代码,您可以在帖子中找到更多详细信息。

创建处理程序类:

// AuthenticationHandler.php
namespace path'to'your'class;
use Symfony'Component'HttpFoundation'Response;
use Symfony'Component'HttpFoundation'RedirectResponse;
use Symfony'Component'Routing'RouterInterface;
use Symfony'Component'HttpFoundation'Session'Session;
use Symfony'Component'Security'Core'Authentication'Token'TokenInterface;
use Symfony'Component'Security'Core'Exception'AuthenticationException;
use Symfony'Component'HttpFoundation'Request;
use Symfony'Component'Security'Core'SecurityContextInterface;
use Symfony'Component'Security'Http'Authentication'AuthenticationSuccessHandlerInterface;
use Symfony'Component'Security'Http'Authentication'AuthenticationFailureHandlerInterface;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
{
    private $router;
    private $session;
    /**
     * Constructor
     *
     * @author  Joe Sexton <joe@webtipblog.com>
     * @param   RouterInterface $router
     * @param   Session $session
     */
    public function __construct( RouterInterface $router, Session $session )
    {
        $this->router  = $router;
        $this->session = $session;
    }
    /**
     * onAuthenticationSuccess
     *
     * @author  Joe Sexton <joe@webtipblog.com>
     * @param   Request $request
     * @param   TokenInterface $token
     * @return  Response
     */
    public function onAuthenticationSuccess( Request $request, TokenInterface $token )
    {
        // if AJAX login
        if ( $request->isXmlHttpRequest() ) {
            $array = array( 'success' => true ); // data to return via JSON
            $response = new Response( json_encode( $array ) );
            $response->headers->set( 'Content-Type', 'application/json' );
            return $response;
        // if form login 
        } else {
            if ( $this->session->get('_security.main.target_path' ) ) {
                $url = $this->session->get( '_security.main.target_path' );
            } else {
                $url = $this->router->generate( 'home_page' );
            } // end if
            return new RedirectResponse( $url );
        }
    }
    /**
     * onAuthenticationFailure
     *
     * @author  Joe Sexton <joe@webtipblog.com>
     * @param   Request $request
     * @param   AuthenticationException $exception
     * @return  Response
     */
     public function onAuthenticationFailure( Request $request, AuthenticationException $exception )
    {
        // if AJAX login
        if ( $request->isXmlHttpRequest() ) {
            $array = array( 'success' => false, 'message' => $exception->getMessage() ); // data to return via JSON
            $response = new Response( json_encode( $array ) );
            $response->headers->set( 'Content-Type', 'application/json' );
            return $response;
        // if form login 
        } else {
            // set authentication exception to session
            $request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception);
            return new RedirectResponse( $this->router->generate( 'login_route' ) );
        }
    }
}

将其注册为服务,并设置为所用防火墙的成功和失败处理程序:

# Resources/config/services.yml
acme.security.authentication_handler:
        class: path'to'your'class'AuthenticationHandler
        public: false
        arguments:
            - @router
            - @session
# app/config/security.yml
security:
    firewalls:
        main:
            form_login:
                check_path:      security_check_route
                success_handler: acme.security.authentication_handler
                failure_handler: acme.security.authentication_handler